OpenGL ES 2.0 Type casting - casting

Is type casting from float to GLfloat safe? I don't care how much precision is lost or gained if it represents the same geometric shape correct enough. I don't wanna port/rewrite all the general library to make it GL compatible. If there is no issue, I am gonna use GL only in critical functions. For example, when writing draw() funciton. That is, casting will be automatic after passing the float parameters to a cube function for example. Can I do that? Is the casting safe enough?

It's absolutely safe and with no loss of precision, since float and GLfloat are exactly the same.
GLfloat merely exists for compatibility between platforms where floats may be defined differently.
In general, though, its declaration is:
typedef float GLfloat;

Related

Passing GLM's vector types to OpenGL via glUniform

Background
I'm currently writing a wrapper around OpenGL's glUniform functions in C++ in an effort to make them type safe. I have a bunch of set_uniform functions that are overloaded to accept either the OpenGL PODs (GLint, GLuint, GLfloat) or any of the GLM vector and matrix types.
I thought it had all been straight forward so far but then I hit a problem with boolean types. GLSL provides provides bool, bec2, bvec3 and bvec4 so I must provide a set_uniform overload for GLboolean as well as the GLM boolean vector types.
According to the OpenGL manual there is no glUniform function that accepts either a GLboolean or a pointer to a GLboolean array. I must pass either GLint, GLuint or GLfloat and the driver will do the conversion for me.
Either the i, ui or f variants may be used to provide values for uniform variables of type bool, bvec2, bvec3, bvec4, or arrays of these. The uniform variable will be set to false if the input value is 0 or 0.0f, and it will be set to true otherwise.
Converting GLboolean to GLint before passing is easy enough but the GLM vector types are proving more difficult. The deeper I go into the implementation the more worried I get about this library.
Problem
The recommended way to pass a GLM vector type to OpenGL is to use glm::value_ptr:
glm::bvec3 v(true, true, false);
glUniform3iv(some_uniform_id, 1, glm::value_ptr(v));
I have a number of problems with this code.
First, glm::bvec3 is implemented as a struct of 3 bools (not GLboolean but C++ bool). I don't believe I should pass it directly since glUniform3iv is expecting a void pointer to some GLints. The C++ spec gives no guarantee over the size of a bool. This means glUniform3iv is potentially reading garbage for the second and third component, or worse, it's actually reading past the end of the array.
To correct this I convert from glm::bvec3 to glm::ivec3 before passing to OpenGL:
glm::bvec3 bv(true, true, false);
glm::ivec3 iv = bv;
glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));
I'm not 100% happy with this since glm::ivec3 has a value type of glm::detail::mediump_int_t which is a typedef for int rather than GLint but maybe this can be chalked up to 'the library designer knows the sizes are the same'.
The second and more major problem is that glm::value_ptr is just passing the address of the first struct member and treating the struct as an array with no regard to padding.
Am I missing something here? The GLM library is very widely used alongside OpenGL, it's even listed on Khronos' own wiki. Yet the function it provides for passing its structures to OpenGL, namely glm::value_ptr, makes no effort to ensure the types it's passing are actually the same size as the types OpenGL expects as well as completely disregarding any padding that may exist. Is the GLM library doing some hidden trickery with regard to type sizes and struct padding so that the data sent to OpenGL is valid or does this library have some serious fundamental problems?
Is the GLM library doing some hidden trickery with regard to type sizes and struct padding so that the data sent to OpenGL is valid or does this library have some serious fundamental problems?
Neither. It's simply making the same assumptions that everyone else does about the behavior of struct layouts and pointer arithmetic.
The C++ standard does not allow value_ptr to work; it is clearly undefined behavior. But it is also a commonly used technique for dealing with such things. Lots of real, functional code out there assumes that a struct { int x; int y;}; can be considered equivalent to an int[2]. And under most C++ implementations, this will all function as expected.
When dealing with low-level programming, it is not unreasonable to make assumptions of this nature.
I'm not 100% happy with this since glm::ivec3 has a value type of glm::detail::mediump_int_t which is a typedef for int rather than GLint but maybe this can be chalked up to 'the library designer knows the sizes are the same'.
That has nothing to do with it. While GLM is called "OpenGL Mathematics", it has no dependency on OpenGL itself. As such, it has no access to GLint or any other OpenGL-defined type.
So you can either assume that ivec3's value_type will be the same type as GLint (you can even write static_asserts to verify it) or you can make your own variation. After all, GLM is templated:
using gl_ivec3 = glm::tvec<GLint, 3>;
...
glm::gl_ivec3 iv = bv;
glUniform3iv(some_uniform_id, 1, glm::value_ptr(iv));

Typedef of Numeric Types

I am using a large physics package, Geant4, for running simulations. There are a number of typedefs defined in the language, and used exclusively throughout the package.
typedef double G4double;
typedef float G4float;
typedef int G4int;
typedef bool G4bool;
typedef long G4long;
I understand the use of typedefs for exposing numeric types as domain-specific types, as this improves readability and allows the typedef to be changed at a later point, if needed. In this case, though, the typedefs are so broad that they do not serve that purpose.
I have also heard of typedefs are being used to ensure a consistent bitsize of each type, as sizeof(int) is not guaranteed by the standard. This cannot be in this case, as these typedefs are always present, rather than being generated by a script after checking the size of the type in question.
What other purposes might there be that I am missing?
Some libraries like to do this to maintain consistency within their code. All types they use (even primitives) start with G4.
In theory you could redefine these on specific platforms if the size of some primitive type causes a problem.
Personally, I've never heard of someone needing to do such. Where specific sizes are required, they're generally used in the first place. But that doesn't mean it hasn't happened.
It's impossible for me to state why this particular library did this. However, I have done similar in my library, and I can give a few reasons, some of which you already mentioned:
It allows you to enhance cross-platform portability without having xintxx_t types floating around.
It allows you to swap out types - possibly at build time. An example of this is if you wanted to have a 3D engine that supported both single and double float precision, you might declare typedef float MyLibraryFloat; or typedef double MyLibraryFloat; triggered by a define macro.
It can help library abstraction. Say you have a library that acts as the front end to several different libraries with (mostly) compatible APIs. Abstracting the types can help this, although it is often not as simple as a typedef in this case.
I think the best reason is the second. It is definitely the most useful if you are dealing with a situation where your types might change based on compiler settings. However, the first is common, especially in older C programs. OpenGL/GLUT does abstraction of types for size safety.

How can one not make assumptions about C++ struct layouts?

I've just learned from Bug in VC++ 14.0 (2015) compiler? that one shouldn't make assumptions about how a struct's layout will end up in memory. However, I don't understand how it is common practice in a lot of code I've seen. For example, the Vulkan graphics API does the following:
Defines a struct
struct {
glm::mat4 projection;
glm::mat4 model;
glm::vec4 lightPos;
} uboVS;
Then fills up its fields:
uboVS.model = ...
uboVS....
Then just copies over the struct (in host memory) to device memory via memcpy:
uint8_t *pData;
vkMapMemory(device, memory, 0, sizeof(uboVS), 0, (void **)&pData);
memcpy(pData, &uboVS, sizeof(uboVS));
vkUnmapMemory(device, memory);
Then over to the GPU, it defines a UBO to match that struct:
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 model;
vec4 lightPos;
} ubo;
Then, on the GPU side, ubo will always match uboVS.
Is this the same undefined behavior? Doesn't that code rely on the uboVS struct to be laid out exactly as defined, or for both sides (the compiled C++ code and the compiled SPIR-V shader) to basically generate the same different struct layout? (similar to the first example in https://www.securecoding.cert.org/confluence/display/c/EXP11-C.+Do+not+make+assumptions+regarding+the+layout+of+structures+with+bit-fields)
This question is not specific to Vulkan or graphics APIs, I am curious as to what exactly can one assume and when is it ok to just use a struct as a chunk of memory. I understand struct packing and alignment, but is there more to it?
Thanks
It's important to recognize the difference between what you did in the question you cite and what you're doing here.
What you did in the question you showed breaks the rules of C++. It invokes undefined behavior. You tried to pretend that an object containing 16 floats is the same thing as a 16-float array. C++ doesn't permit this to be well-defined behavior, and compilers are allowed to assume you won't try it.
By contrast, converting a struct into a byte array and copying that array somewhere else actually doesn't break the rules of the C++ object model. It has a very specific clause permitting such things for appropriate types.
The difference is that it's not the C++ compiler that cares about the object's layout; it's the GPU. So long as the layout of data you provide matches what your shader said it would be, you're fine. You're not casting floats into arrays or trying to access one object through a pointer to a different one or somesuch. You're just copying bytes.
At which point, the only question that remains is whether the byte representation of that struct matches the byte representation of the expected SPIR-V data structure definition. And yes, this is something you can rely upon for most systems that Vulkan can run on.
It is true that, roughly speaking, the C++ standard does not mandate any particular internal layout of class members.
However, specialty libraries, like graphics libraries for a particular operating system, are going to be targeting the operating system's specific compiler. They know how this particular compiler arranges the layout of C/C++ class and structure members, and the library is going to supply suitable definitions that matches the actual hardware in question.
Operating systems that have more than one compiler will often have a formal specification for that operating system's binary ABI, and the compilers are going to follow that ABI, and the specialty library will provide class and structure definitions that will be in sync with that.
So, in your specific case, you can "assume and when is it ok to just use a struct as a chunk of memory" after you consult your compiler's documentation, determine how your compiler lays out the members of structures or classes, and then come up with a structure layout accordingly.
Spir-V (the shading language you pass to vulkan) requires that you add layout decorations to struct members used for UniformConstant, Uniform, and PushConstant variables. You can use this to make the spir-V member offsets match the member offsets in the C++ struct.
To actually do this is tricky as it requires inspecting the spir-V code and setting the offsets as needed.

MPI Different methods to find displacements

Assume that i have a struct type as follows:
typedef struct {
float x, y, z;
float velocity;
int n, type;
} Particle;
I want to send it. I have to create an MPI_Type. I know 4 ways to do it. I listed them below. I want to know what are the differences, limits and benefits of them.
Using MPI_Type_extent
Using offsetof() in stddef.h, it was explained in this answer: MPI Derived Type Send answer
Using MPI_Get_address, also an example in the same answer.
Using reinterpret_cast<const unsigned char*>, i didn't try but there is an example here: MPI Create Custom Data
Option 1 is wrong as per the answer you linked.
Option 2 is the most straightforward, and has the advantage of being a constant expression rather than a function call.
Options 3 and 4 are probably functionally identical, but 3 is safer. Consider:
Advice to users.
C users may be tempted to avoid the usage of MPI_GET_ADDRESS and rely on the availability of the address operator &. Note, however,
that & cast-expression is a pointer, not an address. ISO C does not
require that the value of a pointer (or the pointer cast to int) be
the absolute address of the object pointed at --- although this is
commonly the case. Furthermore, referencing may not have a unique
definition on machines with a segmented address space. The use of
MPI_GET_ADDRESS to "reference" C variables guarantees portability to
such machines as well. ( End of advice to users.)
Source: http://www.mpi-forum.org/docs/mpi-2.2/mpi22-report/node74.htm
Personally, I'd go with option 3, just to make absolutely sure that the values obtained will be compatible with the other MPI calls. You may want to whip up a function or macro similar to offsetof() that uses MPI_Get_address() internally.

complex number types in mixing C(99) and C++

I'm writing a math library, the core of it is in C++. Later it may be implemented in pure C (C99 I suppose). I think I need a C like API so that I can get Python and matlab and the like to use the library. My impression is that doing this with C++ is painful.
So is there a good or standard or proper way to cast between double complex *some_array_in_C99, and complex<double> *some_array_in_cpp ?
I could just use void *pointers, but I'm not sure if that's good.
This may be nitpicking, because ctypes seems to work fine with complex<double>, but I'm worried about matlab and other possible numerical environments.
The C99 and C++0x standards both specify that their respective double complex types must have the same alignment and layout as an array of two doubles. This means that you can get away with passing arguments as a void * and have your routines be (relatively) easily callable from either language, and this is an approach that many libraries have taken.
The C++0x standard guarantees (ยง26.4) that a reinterpret_cast of std::complex<double>* to double* will do the right thing; if I remember correctly, this was not so clearly specified in earlier versions of the standard. If you are willing to target C++0x, it may be possible for you to use this to do something cleaner for your interfaces.
Given that the actual layout and alignment specifications are defined to agree, I would be tempted to just condition the type in the header file on the language; your implementation can use either language, and the data will be laid out properly in memory either way. I'm not sure how MATLAB does things internally though, so I don't know if this is compatible with MATLAB or not; if they use the standard LAPACK approach, then it will be on many but not all platforms in all circumstances; LAPACK defines its own double complex type to be a struct with two double members, which will usually be laid out the same way in memory (this isn't guaranteed), but could follow a different calling convention on some platforms.