Are you using WebGL, or some other JavaScript-based runtime?
Are you using WebGL, or some other JavaScript-based runtime?
No WebGL, I don't like "ES". I made a c++ extension for nodejs. It allows me to use opengl 4.3 and compatibility context or core so getting off the ground is quick.
A whole mess of calls, see below a simple snippet. The javascript calls OpenGL::vertexAttrib4Ii, which queues an APC in the gui thread calling APC_vertexAttrib4Ii, that executes it. Calling c++ from javascript is super super slow. So calling vertexAttrib4Ii in immediate mode, a bunch of times was crawling, >500ms per frame. When I used a display list, back to super fast, but not dynamic. Using glMulti*Indirect it was back to super fast, so I think it is the right direction for me.
VOID CALLBACK OpenGL::APC_vertexAttrib4Ii(__in ULONG_PTR dwParam){
PParam8 params = (PParam8)dwParam;
PSLIST_ENTRY entry = (PSLIST_ENTRY)dwParam;
params->obj->glVertexAttribI4iv(params->i32args[0], ¶ms->i32args[1]);
glGetErrorFileLine(params->obj->tryError(TEXT("glVertexAttribI4iv")));
freeParam8(params);
}
Handle<Value> OpenGL::vertexAttrib4Ii(const Arguments& args) {
HandleScope scope;
if(args.Length() < 5){
return scope.Close(Undefined());
}
OpenGL *obj = OpenGL::Unwrap<OpenGL>(args.This());
PParam8 params = getParam8();
params->obj = OpenGL::Unwrap<OpenGL>(args.This());
params->i32args[0] = argnint(args, 0);
params->i32args[1] = argnint(args, 1);
params->i32args[2] = argnint(args, 2);
params->i32args[3] = argnint(args, 3);
params->i32args[4] = argnint(args, 4);
DWORD success = QueueUserAPC(APC_vertexAttrib4Ii, obj->threadHandle, (ULONG_PTR)params);
if(!success){
DWORD err = GetLastError();
OutputDebugString(TEXT("vertexAttrib4Ni" L" error\n"));
}
return scope.Close(Undefined());
}
If you are a nodejs junky, I might pass it your way if you are interested.
Through lots of magical macro work, see below, the calls define, and instantiate both calls and the apc and everything. The code above is part of what one line gets expanded to.
glGen(genBuffer, params->obj->glGenBuffers);
glGen(genFramebuffer, params->obj->glGenFramebuffers);
glGen(genProgramPipeline, params->obj->glGenProgramPipelines);
glGen(genQuery, params->obj->glGenQueries);
glGen(genRenderbuffer, params->obj->glGenRenderbuffers);
glGen(genSampler, params->obj->glGenSamplers);
glGen(genTexture, glGenTextures);
glGen(genTransformFeedback, params->obj->glGenTransformFeedbacks);
glGen(genVertexArray, params->obj->glGenVertexArrays);
glMethod0(end, glEnd);
glMethod0(loadIdentity, glLoadIdentity);
glMethod0(endList, glEndList);
glMethod_u(activeTexture, params->obj->glActiveTexture);
glMethod_u(clear, glClear);
glMethod_u(enableClientState, glEnableClientState);
glMethod_u(enable, glEnable);
glMethod_u(frontFace, glFrontFace);
glMethod_u(cullFace, glCullFace);
glMethod_u(disable, glDisable);
glMethod_u(begin, glBegin);
glMethod_u(generateMipmap, params->obj->glGenerateMipmap);
glMethod_u(callList, glCallList);
glMethod_eo(bindTexture, glBindTexture);
glMethod_eo(bindTransformFeedback, params->obj->glBindTransformFeedback);
glMethod_eo(bindBuffer, params->obj->glBindBuffer);
glMethod_eo(bindFramebuffer, params->obj->glBindFramebuffer);
glMethod_eo(bindRenderbuffer, params->obj->glBindRenderbuffer);
glMethod_eo(bindSampler, params->obj->glBindSampler);
glMethod_eo(beginQuery, params->obj->glBeginQuery);
glMethod_e(endQuery, params->obj->glEndQuery);
glMethod_uu(hint, glHint);
glMethod_uu(newList, glNewList);
glMethod_uuu(texParameteri, glTexParameteri);
glMethod_f(clearDepth, glClearDepth);
glMethod_ff(depthRange, glDepthRange);
glMethod_fff(scale, glScalef);
glMethod_ffff(clearColor, glClearColor);
glMethod_ffff(texCoord4f, glTexCoord4f);
glMethod_ffff(vertex4f, glVertex4f);
glMethod_ffff(color4f, glColor4f);
glMethod_uuuu(color4ub, glColor4ub);
glMethod_iiii(vertex4i, glVertex4i);
glMethod_ffff(rotate, glRotatef);
glMethod_uuuuu(texStorage2D, params->obj->glTexStorage2D);
glMethod_uuuuuu(texStorage3D, params->obj->glTexStorage3D);
glMapBuffer, how I mock thee!
Anyway, I am now playing with glMapBuffer, drawing 75,000 quads with 30 FPS and glMapBuffer-ing all of those vertices every frame. Quite a nice performance, though I have to ask:
When creating a GUI, should I scratch the buffer as I do now and reconstruct all of the vertices every frame, even if only a handful of gui elements change? At first it seems wasteful, but I wouldn't have to keep any state of the vertices, I could just fill the buffer as I go along.
Or should I instead map the buffer, write only the changes that occur in that frame at once?
Or throw away glMapBuffer and use glBufferSubData? I've read the PDF, so I know that glMapBuffer should be the winner, but I've read this - http://www.stevestreeting.com/2007/0...w-i-mock-thee/ and it made me a little bit suspicious.
I read that link, the replies at the bottom indicate that writer wasn't orphaning the buffers before mapping them. This causes the mapping process to read back from the gpu the buffer and bring it to the cpu. Orphaning is glBufferData with null for data pointer, it lets the GL know the buffer is no longer needed. After orphaning, the glMapBuffer command maps a new buffer causing no readback, and is much faster. That assumes the GL driver doesn't get badly confused by the whole process. Orphaning is how the article I posted gets the good numbers with glMapBuffer.
They indicate no such thing. In the writer's own words: Yep, that's what they say, but it doesn't work. I went through all the papers and tips articles I could find and tried all combinations of glBufferData with NULL pointers, all the access modes. Nada.
That's what has got me worried. I will of course test all of this on my own, I just wanted something of a last-minute reassurance that glMapBuffer is a good way to update a lot of disconnected parts of a buffer, which it seems to be.
Anyway, your PDF was very helpful, I appreciate it.
Did you read the very next page? http://www.stevestreeting.com/2007/0...ta-the-return/They indicate no such thing. In the writer's own words: Yep, that's what they say, but it doesn't work. I went through all the papers and tips articles I could find and tried all combinations of glBufferData with NULL pointers, all the access modes. Nada.
Also, this is from like five years ago. I wouldn't trust any OpenGL performance information that old.
I haven't, I stand corrected. And I didn't trust it, that's why I asked here.![]()