Passing zero count to glUniform4fv: specification vs Emscripten implementation - opengl

My application is written in C++ using OpenGL API, and I build it for desktop OS, as well as for web, using Emscripten. Not so long ago a strange bug emerged: everything works okay on desktop (with any optimizations, valgrind-clean), but crashes in WebGL with the following error:
exception thrown: TypeError: Argument 2 of
WebGLRenderingContext.uniform4fv could not be converted to any of:
Float32Array, UnrestrictedFloatSequence.
I built it with -g4 (generate readable JS code with debug info) and figured out that sometimes glUniform4fv gets zero as it's count argument. OpenGL call wrapper generated by Emscripten is the following:
function _glUniform4fv(location, count, value) {
var view;
if (4*count <= GL.MINI_TEMP_BUFFER_SIZE) {
// avoid allocation when uploading few enough uniforms
view = GL.miniTempBufferViews[4*count-1];
for (var i = 0; i < 4*count; i += 4) {
view[i] = HEAPF32[(((value)+(4*i))>>2)];
view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)];
view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)];
view[i+3] = HEAPF32[(((value)+(4*i+12))>>2)];
}
} else {
view = HEAPF32.subarray((value)>>2,(value+count*16)>>2);
}
GLctx.uniform4fv(GL.uniforms[location], view);
}
So when this wrapper gets zero count and enters first branch, it executes view = GL.miniTempBufferViews[-1];, which is undefined. This value goes to GLctx.uniform4fv, yielding the above error.
Ok, let's take a look at OpenGL documentation, ES 2.0 version, which is base for WebGL1:
count
Specifies the number of elements that are to
be modified. This should be 1 if the targeted
uniform variable is not an array, and 1 or more if it is
an array.
...
Errors
...
GL_INVALID_VALUE is generated if count is less than 0.
So I can't see anything about what OpenGL should do when count is zero. I assumed, that it's a correct value, when we have nothing to pass to a shader. At least, it shouldn't crash.
So I have the following questions:
1) Is it undefined or implementation-defined behavior from the respect of GLES 2.0 specification?
2) What should be Emscripten's correct reaction? It's definitely not allowed to set error state as there is no such error in specs. But maybe it would be more correct to pass zero-sized Float32Array to GLctx.uniform4fv, letting browser's Webgl implementation to deal with it? Should I report an issue to Emscripten developers?

Related

GLSL dynamic looping not working on Intel UHD Graphics [duplicate]

I asked for help about an OpenGL ES 2.0 Problem in this question.
What seems to be the answer is very odd to me.
Therefore I decided to ask this question in hope of being able to understand what is going on.
Here is the piece of faulty vertex-shader code:
// a bunch of uniforms and stuff...
uniform int u_lights_active;
void main()
{
// some code...
for ( int i = 0; i < u_lights_active; ++i )
{
// do some stuff using u_lights_active
}
// some other code...
}
I know this looks odd but this is really all code that is needed to explain the problem / faulty behavior.
My question is: Why is the loop not getting executed when I pass in some value greater 0 for u_lights_active?
When I hardcode some integer e.g. 4, instead of using the uniform u_lights_active, it is working just fine.
One more thing, this only appears on Android but not on the Desktop. I use LibGDX to run the same code on both platforms.
If more information is needed you can look at the original question but I didn't want to copy and paste all the stuff here.
I hope that this approach of keeping it short is appreciated, otherwise I will copy all the stuff over.
Basically GLSL specifies that implementations may restrict loops to have "constant" bounds on them. This is to make it simpler to optimize the code to run in parallel (different loop counts for different pixels would be complex). I believe on some implementations the constants even have to be small. Note that the spec just specifies the "minimum" behavior, so some devices might support more complex loop controls than the spec requires.
Here's a nice summary of the constraints:
http://www.khronos.org/webgl/public-mailing-list/archives/1012/msg00063.html
Here's the GLSL spec (look at section 4 of Appendix A):
http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
http://www.opengl.org/discussion_boards/showthread.php/171437-can-for-loops-terminate-with-a-uniform
http://www.opengl.org/discussion_boards/showthread.php/177051-GLSL-loop-problem-on-Radeon-HD-cards
http://www.opengl.org/discussion_boards/showthread.php/162722-Problem-when-using-uniform-variable-as-a-loop-count-in-fragment-shader
https://www.opengl.org/discussion_boards/showthread.php/162535-variable-controlled-for-loops
If you have a static loop it can be unrolled and made into static constant lookups. If you absolutely need to make it dynamic, you'll need to store indexed data into a 1D texture and sample that instead.
I'm guessing that the hardware on the desktop is more advanced than on the tablet. Hope this helps!
Kind of a fun half-answer, and-or, the solution to the underlying problem that I have chosen.
The following function called with 'id' passed as the ID of the shader's script block and 'swaps' filled with an array of 2 component arrays in the format of [[ThingToReplace, ReplaceWith],] strings. Called before the shader is created.
In the javascript:
var ReplaceWith = 6;
function replaceinID(id,swaps){
var thingy = document.getElementById(id);
for(var i=0;i<swaps.length;i++){
thingy.innerHTML = thingy.innerHTML.replace(swaps[i][0], swaps[i][1]);
}
}
replaceinID("My_Shader",[['ThingToReplace',ReplaceWith],]);
Coming from C, this is a very Macro like approach, in that it simulates a preprocessor.
In the GLSL:
for(int i=0;i<ThingToReplace;i++){
;//whatever goes here
}
Or;
const int val = ThingToReplace;
for(int i=0;i<val;i++){
;//whatever goes here
}

QVariant::value<T>() fails to convert unless QVariant::fromValue<T>() has been called previously. Is this expected behaviour?

Using Qt 6.2.1 with Microsoft MSVC 2019 under Windows.
Given this function to load a list of unsigned ints from persistent settings:
QList<uint> get(QSettings& settings, QString& key) {
QVariant v {settings.value(key)}
return v.value<QList<uint>>();
}
The call to v.value() will sometimes fail to convert the value stored in the QVariant, producing this debug message:
QVariant::load: unknown user type with name QList<uint>
The inverse function to store a list always works fine:
void set(QSettings& settings, QString& key, QList<uint> list) {
QVariant v {QVariant::fromValue<QList<uint>>(list)};
settings.setValue(key, v);
}
After some debugging, I narrowed down the situations in which the first function fails. It seems it has to do with the registered metatype for the type QList<uint> and its registered data stream operators.
If during the execution of the program the following code has been executed at least once at any point before calling get(), the problematic QVariant conversion will complete without error:
// Either this one
QVariant::fromValue<QList<uint>>(list);
// or these
auto mt = QMetaType::fromType<QList<uint>>();
mt.hasRegisteredDataStreamOperators();
Is this by design or a bug in Qt 6?
This asymmetric behaviour between QVariant::value and QVariant::fromValue is puzzling.
For now, I am getting around the issue by adding dummy calls to force MetaType registration or whatever is going on in the background:
QVariant::fromValue<QList<uint>>(QList<uint>{}); // Dummy call
return v.value<QList<uint>>();
but this feels like a bad hack. If this is not a bug, there surely is a better way. Can anyone shed some light on this matter?
Note qRegisterMetaTypeStreamOperators("name") has been removed in Qt 6.
PS: The example code above is a very simplified version of the real code I am working on.

Detecting orientation of iPhone using C++

Embarcadero C++Builder 10.3.2 Enterprise
Searching the internet, I could not find any FMX code for this. Based on Delphi code, this should have worked but the compiler does not like it
if (Application->FormFactor->Orientations == Fmx::Types::TScreenOrientations::Landscape) {
//Landscape
}
Also, the value of Application->FormFactor->Orientations is the same whatever the orientation of the iphone. {System::SetBase = {Data = {[0] = 11 '\v'}}}
How does one determine the orientation?
The Orientations property is a TFormOrientations, which is a System::Set of TFormOrientation values. You can't use Set::operator== to compare it to a single value, which is why you are getting a compiler error. However, you can use the Set::Contains() method to check if it has a given value, eg:
if (Application->FormFactor->Orientations.Contains(Fmx::Forms::TFormOrientation::Landscape)) {
//...
}
In any case, the Orientations property specifies which orientation(s) the application's Forms are allowed to take (a value of 11 has its 1st, 2nd, and 4th bits set to 1, which correspond to the Portrait, Landscape, and InvertedLandscape orientations being enabled). It does not report what the device's current orientation is. For that, use the IFMXScreenService::GetScreenOrientation() method instead, eg:
_di_IFMXScreenService ScreenService;
if (TPlatformServices::Current->SupportsPlatformService(__uuidof(IFMXScreenService), &ScreenService)) {
if (ScreenService->GetScreenOrientation() == Fmx::Types::TScreenOrientation::Landscape) {
//...
}
}

What's the SDL-2.0 corresponding function for 'SDL_JoystickOpened'?

I tried to use SDL_JoystickOpened() in a SDL-2.0 code, but I got the error message SDL_JoystickOpened was not declared in this scope.
I've searched and found that SDL_JoystickOpened() no longer exists in SDL-2.0, but I didn't find the function that replaced it. Can anyone please tell me how can I replace SDL_JoystickOpened() in this piece of code:
SDL_Joystick *joy = SDL_JoystickOpen(0);
if (SDL_JoystickOpened(0) == 1)
{
// do something
}
Thanks.
The documentation says the SDL_JoystickOpen() call returns a NULL pointer if it fails so just do a check for that:
SDL_Joystick *joy = SDL_JoystickOpen(0);
if (joy) {
// joy is a valid pointer so do stuff
}
An alternative in 2.0 could be SDL_JoystickGetAttached
SDL_JoystickOpened(int index) (The old way SDL 1.2)
Determines whether a joystick has already been opened within the application. index refers to the N'th joystick on the system.
SDL_JoystickGetAttached(SDL_Joystick* joystick) (The new way SDL 2.0)
Returns SDL_TRUE if the joystick has been opened, SDL_FALSE if it has not; call SDL_GetError() for more information
There is also an example in test/testjoystick.c of SDL2 source-code (at least in SDL2-2.0.1).
Also note the Joysticks section of the SDL 1.2 to 2.0 Migration Guide. It gives various information on new features and ways in 2.0. It also links to the GameController section with e.g. SDL_GameControllerGetJoystick.

How do I read OpenGL dependencies?

I have a question about OpenGL dependencies. For example, for ARB_shader_atomic_counters, the dependency section says this:
Dependencies
This extension is written against the OpenGL 4.1 (core) specification
and the GLSL 4.10.6 specification.
OpenGL 3.0 is required.
How do I read this information? Does the graphics card and/or driver need to support OpenGL 4.1 or OpenGL 3.0?
The official docs say:
Extensions may be written against a particular specification version, but it is possible to implement them that extension on older OpenGL versions. Some extensions can be implemented even on OpenGL 1.1, while others have a higher base version. The minimum version that the extension can appear in is specified with the text "X are required"
Is this just a theoretical possibility, and few (if any) drivers will implement it? Or would some drivers provide this function on OpenGL 3 hardware? How can I find out whether it is implemented?
You really should not read too much into those if you can help it. That information is not particularly helpful to the average developer. You will likely never encounter a GL 3.0 implementation that implements this extension because it was designed around a Shader Model 5.0 (DX 11) hardware feature. In theory there is nothing preventing it from being implemented in 3.0, but in practice no hardware/driver combination that implements this extension is going to limit itself to 3.0.
If you were going to implement the extension or devise some alternative solution, then it would be tremendously helpful to know the absolute minimum API version necessary.
When it says it is written against a certain version of a specification, what that means is that anytime the extension specification says something to the effect of "Add the following language to section X, paragraph Y, ...", you will find the original unextended text in that specific spec. version. It also means that the extension makes certain assumptions about how things behave.
For example, if version X says that points are rasterized as hexagons and version Y says they are rasterized as circles, and an extension is written against version Y, then the extension is free to assume that points are rasterized as circles. If this assumption becomes a point of controversy, you will find a blurb about it in the "Issues" section.
As for determining whether the extension is implemented (which is the most important point from your perspective), that is what the GL_EXTENSIONS string is for. Be aware, however, that the way you query this string has changed over the years:
In a compatibility profile context or GL 3.1 or older:
// Returns a massive null terminated string containing every extension the
// implementation supports.
//
// ... do a string search to find your extension.
const GLchar* exts = glGetString (GL_EXTENSIONS);
In a core profile context:
GLint num_exts;
glGetIntegerv (GL_NUM_EXTENSIONS, &num_exts);
for (int i = 0; i < num_exts; i++) {
// Returns a null terminated string containing only one extension
const GLchar* ext = glGetStringi (GL_EXTENSIONS, i);
}
If you try to do the former in a core profile, GL will generate a GL_INVALID_ENUM error and do nothing else. This is the reason glewExperimental = GL_TRUE is necessary before calling glewInit (...) if you use GLEW in a core profile.