Panda3d and templates

They do not get along right?

Function:

template<typename T>
CPTA(T)fetch_ptr_parameter(...){
 ...
}

Error:

:display(warning): Unable to load: /usr/local/panda3d/lib/libglgsg.so: undefined symbol: _ZN21GraphicsStateGuardian19fetch_ptr_parameterIfEEPK14PointerToArrayIT_ERKN6Shader13ShaderPtrSpecIS2_EE

Any possible solution other then having to duplicate each function three times (int, float, double) ?

Federico

Uh, are you defining a template member function of GraphicsStateGuardian? I don’t know why that wouldn’t work, but it’s really between you and the compiler–there’s nothing about Panda3D that precludes the use of templates.

David

Yes, I wanted a template member function of GraphicsStateGuardian, but I forgot it’s not possible to split definition and declaration of function templates. I saw the weird error and I thought was something related to panda3D.

Problem solved then.
Thanks

Are you sure using templates is not going to cause any problem in this case:

template <typename T>
INLINE ShaderInput(InternalName *id, const PTA(T) &ptr, int priority=0);
(Probably I should remove INLINE and the constructor should be defined in the header)

and in this case (in shaderAttrib.h):

const PTA(float) &get_shader_input_ptr(InternalName *id) const { 
 ...
}

and even if it works is coherent to use templates? Except in some cases I haven’t seem them much in the source code.
I am asking you this because I have added a NodePath::set_shader_input(PTA(float)), and I am not sure how to generalize it to int and double.

We do generally resist the heavy use of templates in Panda3D code. There are several reasons for this; one of them is that we first started to develop Panda over ten years ago, when compiler support for template features was not very broad. Even today, there remain some issues with templates and the MSVS compiler, particularly with respect to DLL’s. Still, most kinds of template uses are supported across all of the compilers that we currently use to build Panda, so compiler support is less of an issue today.

Other reasons for avoiding heavy template use include minimizing code bloat and compiler time, maximizing code readability, and most importantly, maintaining good support for Python. interrogate can handle templates, to a certain extent, but it does require some hand-holding to do so, and template member functions can be problematic.

In this case, I wonder if there’s any value at all in supporting anything other that PTA(float). Surely the GPU in any modern graphics card only handles single-precision floats anyway, and an array of ints and an array of doubles is just going to get turned into an array of floats by the driver before shipping the data to the GPU. So why bother bloating the interface?

On the other hand, if you really wanted to make the code as generic as possible, we could use a GeomVertexArrayData instead of a PTA(), which allows any kind of numeric array at all.

David

If this were the case it would be unnecessary supporting PTA() of ints and doubles. But I am not sure about it, take a look at the list of inputs supported by Cg 2.0:

pastebin.com/f6832b8a0.

I am pretty sure the drivers handle the cast to half and fixed, and I think there is no casting involved for double and int,because the functions:

void cgGLSetParameter#dv(CGparameter parameter,
                         const double* array);

void cgGLSetParameter#iv(CGparameter parameter,
                         const int* array);

are explicitly expecting double* or int*.

I was thinking that I just need to bring around some numbers. There is no need of PTA() vectors or GeomVertexDataArray, so what about just having:

that if filled by a function set_shader_input(PTA(float | double | int)) or something else compatible with interrogate ?

The list of inputs accepted by Cg is meaningless. Cg is just following the example of OpenGL, which accepts everything possible, and converts it internally as needed. The real question is what is actually supported by the hardware, which you cannot determine by looking at the interface.

(Of course, there’s a corollary question of what might ever be supported by hardware years down the road; and this is why OpenGL and Cg try to be general. But I’m not sure if there is value in this same kind of long-view generality for Panda’s purposes.)

Still, I don’t really know what the hardware supports today; and it’s certainly possible that it does accept doubles and ints.

You can’t store a PTA(float) in a float *, because that doesn’t keep the reference count, and the array might be immediately deleted. If you really wanted a structure that had those three pointers, it would have to store them as PTA(int), PTA(float), and PTA(double). That’s perfectly OK, of course.

David

The list of inputs accepted by Cg is meaningless. Cg is just following the example of OpenGL, which accepts everything possible, and converts it internally as needed. The real question is what is actually supported by the hardware, which you cannot determine by looking at the interface.

Thanks for the information. I’ll take a deeper look at this before adding useless stuff.

Sorry I wasn’t clear enough. I was thinking:

memcpy(data,(PTA(...)->v()),sizeof(float)*n);

You are right.

Table 3-3. Data Types for Various Profiles
http.developer.nvidia.com/CgTuto … ter03.html (not updated to Cg 2.0 by the way.)

I am still wondering how these data types are handled. I mean when they say: Floating-point clamped to integers and my input is an int: are the drivers turning my int into a float, and then back into an interger, before shipping it to the GPU?

OK, but now you have to be responsible for allocating and eventually freeing the memory block that corresponds to ‘data’. This is the sort of problem that PTA(…) was designed to handle for you automatically.

I believe they mean the driver turns the int into a float, and then ships it to the GPU as a float. I understand “clamped to integers” simply to mean that the floats will contain integer values, but they’re still floats.

David

Awesome, I’ll definitely use PTA(…) then. Plus PTA(int) copy = array; equals int *copy = array; right?

I have one more question:
Do you think it worth calling memcmp(new PTA(…), cached PTA(…)) in CLP(ShaderContext)::issue_parameters(…)
before sending the data to the GPU?

If by this you mean that PTA assignment is by pointer, and not by value, that is correct. Assigning one PTA to another simply assigns the pointer value (and increments the reference count), and does not copy the data itself.

Do you mean to ask, is it worthwhile to copy the data itself, instead of just copying the pointer? I don’t think that sounds worthwhile. It’s additional overhead, and it doesn’t sound terribly useful.

David

Do you mean to ask, is it worthwhile to copy the data itself, instead of just copying the pointer? I don't think that sounds worthwhile. It's additional overhead, and it doesn't sound terribly useful. 

No I meant compare the data with memcmp() to figure out if the they changed in the current frame and thus must be resent to GPU.

Hm… it would make sense to store a copy at the ShaderContext then, but be careful with textures. They keep a pointer to the data, and the data can change without the texture object changing.

Hm... it would make sense to store a copy at the ShaderContext then, but be careful with textures. They keep a pointer to the data, and the data can change without the texture object changing.

I see, thanks for pointing this out.