def invokeFunction(self, function): # Infer the drawable size from GL calls if function.name == "glViewport": print ' glretrace::updateDrawable(x + width, y + height);' if function.name == "glViewportArray": # We are concerned about drawables so only care for the first viewport print ' if (first == 0 && count > 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedf": print ' if (index == 0) {' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedfv": print ' if (index == 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'): # Some applications do all their rendering in a framebuffer, and # then just blit to the drawable without ever calling glViewport. print ' glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));' if function.name == "glEnd": print r' if (currentContext) {' print r' currentContext->insideBeginEnd = false;' print r' }' if function.name == 'memcpy': print ' if (!dest || !src || !n) return;' # Skip glEnable/Disable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) as we don't # faithfully set the CONTEXT_DEBUG_BIT_ARB flags on context creation. if function.name in ('glEnable', 'glDisable'): print ' if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) return;' # Destroy the buffer mapping if self.unmap_function_regex.match(function.name): print r' GLvoid *ptr = NULL;' if function.name == 'glUnmapBuffer': print r' glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapBufferARB': print r' glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);' elif function.name == 'glUnmapBufferOES': print r' glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);' elif function.name == 'glUnmapNamedBuffer': print r' glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapNamedBufferEXT': print r' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapObjectBufferATI': # TODO pass else: assert False print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' } else {' print r' retrace::warning(call) << "failed to get mapped pointer\n";' print r' }' # Implicit destruction of buffer mappings # TODO: handle BufferData variants # TODO: don't rely on GL_ARB_direct_state_access if function.name in ('glDeleteBuffers', 'glDeleteBuffersARB'): print r' if (currentContext->features().ARB_direct_state_access) {' print r' for (GLsizei i = 0; i < n; ++i) {' print r' GLvoid *ptr = nullptr;' print r' glGetNamedBufferPointerv(buffers[i], GL_BUFFER_MAP_POINTER, &ptr);' print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' }' print r' }' print r' }' if function.name.startswith('glCopyImageSubData'): print r' if (srcTarget == GL_RENDERBUFFER || dstTarget == GL_RENDERBUFFER) {' print r' retrace::warning(call) << " renderbuffer targets unsupported (https://github.com/apitrace/apitrace/issues/404)\n";' print r' }' is_draw_arrays = self.draw_arrays_function_regex.match( function.name) is not None is_draw_elements = self.draw_elements_function_regex.match( function.name) is not None is_misc_draw = self.misc_draw_function_regex.match( function.name) is not None profileDraw = (is_draw_arrays or is_draw_elements or is_misc_draw or function.name == 'glBegin' or function.name.startswith('glDispatchCompute')) # Keep track of current program/pipeline if function.name in ('glUseProgram', 'glUseProgramObjectARB'): print r' if (currentContext) {' print r' currentContext->currentUserProgram = call.arg(0).toUInt();' print r' currentContext->currentProgram = %s;' % function.args[ 0].name print r' }' if function.name in ('glBindProgramPipeline', 'glBindProgramPipelineEXT'): print r' if (currentContext) {' print r' currentContext->currentPipeline = %s;' % function.args[ 0].name print r' }' # Only profile if not inside a list as the queries get inserted into list if function.name == 'glNewList': print r' if (currentContext) {' print r' currentContext->insideList = true;' print r' }' if function.name == 'glEndList': print r' if (currentContext) {' print r' currentContext->insideList = false;' print r' }' if function.name == 'glBegin' or \ is_draw_arrays or \ is_draw_elements or \ function.name.startswith('glBeginTransformFeedback'): print r' if (retrace::debug) {' print r' _validateActiveProgram(call);' print r' }' if function.name != 'glEnd': print r' if (currentContext && !currentContext->insideList && !currentContext->insideBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::beginProfile(call, true);' else: print r' glretrace::beginProfile(call, false);' print r' }' if function.name in ('glCreateShaderProgramv', 'glCreateShaderProgramEXT', 'glCreateShaderProgramvEXT'): # When dumping state, break down glCreateShaderProgram* so that the # shader source can be recovered. print r' if (retrace::dumpingState) {' print r' GLuint _shader = glCreateShader(type);' print r' if (_shader) {' if not function.name.startswith('glCreateShaderProgramv'): print r' GLsizei count = 1;' print r' const GLchar **strings = &string;' print r' glShaderSource(_shader, count, strings, NULL);' print r' glCompileShader(_shader);' print r' const GLuint _program = glCreateProgram();' print r' if (_program) {' print r' GLint compiled = GL_FALSE;' print r' glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);' if function.name == 'glCreateShaderProgramvEXT': print r' glProgramParameteriEXT(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);' else: print r' glProgramParameteri(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);' print r' if (compiled) {' print r' glAttachShader(_program, _shader);' print r' glLinkProgram(_program);' print r' if (false) glDetachShader(_program, _shader);' print r' }' print r' // TODO: append shader info log to program info log' print r' }' print r' glDeleteShader(_shader);' print r' _result = _program;' print r' } else {' print r' _result = 0;' print r' }' print r' } else {' Retracer.invokeFunction(self, function) print r' }' elif function.name in ('glDetachShader', 'glDetachObjectARB'): print r' if (!retrace::dumpingState) {' Retracer.invokeFunction(self, function) print r' }' elif function.name == 'glClientWaitSync': print r' _result = glretrace::clientWaitSync(call, sync, flags, timeout);' print r' (void)_result;' elif function.name == 'glGetSynciv': print r' if (pname == GL_SYNC_STATUS &&' print r' bufSize >= 1 &&' print r' values != NULL &&' print r' call.arg(4)[0].toSInt() == GL_SIGNALED) {' print r' // Fence was signalled, so ensure it happened here' print r' glretrace::blockOnFence(call, sync, GL_SYNC_FLUSH_COMMANDS_BIT);' print r' (void)length;' print r' }' else: Retracer.invokeFunction(self, function) # Ensure this context flushes before switching to another thread to # prevent deadlock. # TODO: Defer flushing until another thread actually invokes # ClientWaitSync. if function.name.startswith("glFenceSync"): print ' if (currentContext) {' print ' currentContext->needsFlush = true;' print ' }' if function.name in ("glFlush", "glFinish"): print ' if (currentContext) {' print ' currentContext->needsFlush = false;' print ' }' if function.name == "glBegin": print ' if (currentContext) {' print ' currentContext->insideBeginEnd = true;' print ' }' print r' if (currentContext && !currentContext->insideList && !currentContext->insideBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::endProfile(call, true);' else: print r' glretrace::endProfile(call, false);' print r' }' # Error checking if function.name.startswith('gl'): # glGetError is not allowed inside glBegin/glEnd print ' if (retrace::debug && currentContext && !currentContext->insideBeginEnd) {' print ' glretrace::checkGlError(call);' if function.name in ('glProgramStringARB', 'glLoadProgramNV'): print r' GLint error_position = -1;' print r' glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);' print r' if (error_position != -1) {' print r' const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);' print r' retrace::warning(call) << "error in position " << error_position << ": " << error_string << "\n";' print r' }' if function.name == 'glCompileShader': print r' GLint compile_status = 0;' print r' glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);' print r' if (!compile_status) {' print r' retrace::warning(call) << "compilation failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in ('glLinkProgram', 'glCreateShaderProgramv', 'glCreateShaderProgramEXT', 'glCreateShaderProgramvEXT', 'glProgramBinary', 'glProgramBinaryOES'): if function.name.startswith('glCreateShaderProgram'): print r' GLuint program = _result;' print r' GLint link_status = 0;' print r' glGetProgramiv(program, GL_LINK_STATUS, &link_status);' print r' if (!link_status) {' print r' retrace::warning(call) << "link failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetProgramInfoLog(program, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glCompileShaderARB': print r' GLint compile_status = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);' print r' if (!compile_status) {' print r' retrace::warning(call) << "compilation failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glLinkProgramARB': print r' GLint link_status = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);' print r' if (!link_status) {' print r' retrace::warning(call) << "link failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if self.map_function_regex.match(function.name): print r' if (!_result) {' print r' retrace::warning(call) << "failed to map buffer\n";' print r' }' if self.unmap_function_regex.match( function.name) and function.type is not stdapi.Void: print r' if (!_result) {' print r' retrace::warning(call) << "failed to unmap buffer\n";' print r' }' if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_result != _origResult) {' print r' retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";' print r' }' if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatus', 'glCheckNamedFramebufferStatusEXT'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_origResult == GL_FRAMEBUFFER_COMPLETE &&' print r' _result != GL_FRAMEBUFFER_COMPLETE) {' print r' retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";' print r' }' print ' }' # Query the buffer length for whole buffer mappings if self.map_function_regex.match(function.name): if 'length' in function.argNames(): assert 'BufferRange' in function.name else: assert 'BufferRange' not in function.name print r' GLint length = 0;' if function.name in ('glMapBuffer', 'glMapBufferOES'): print r' glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapBufferARB': print r' glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);' elif function.name == 'glMapNamedBuffer': print r' glGetNamedBufferParameteriv(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapNamedBufferEXT': print r' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapObjectBufferATI': print r' glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);' else: assert False
def invokeFunction(self, function): # Infer the drawable size from GL calls if function.name == "glViewport": print ' glretrace::updateDrawable(x + width, y + height);' if function.name == "glViewportArray": # We are concerned about drawables so only care for the first viewport print ' if (first == 0 && count > 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedf": print ' if (index == 0) {' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedfv": print ' if (index == 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'): # Some applications do all their rendering in a framebuffer, and # then just blit to the drawable without ever calling glViewport. print ' glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));' if function.name == "glEnd": print ' glretrace::insideGlBeginEnd = false;' if function.name.startswith('gl') and not function.name.startswith('glX'): print r' if (retrace::debug && !glretrace::currentContext) {' print r' retrace::warning(call) << "no current context\n";' print r' }' if function.name == 'memcpy': print ' if (!dest || !src || !n) return;' # Skip glEnable/Disable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) as we don't # faithfully set the CONTEXT_DEBUG_BIT_ARB flags on context creation. if function.name in ('glEnable', 'glDisable'): print ' if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) return;' # Destroy the buffer mapping if function.name in self.unmap_function_names: print r' GLvoid *ptr = NULL;' if function.name == 'glUnmapBuffer': print r' glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapBufferARB': print r' glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);' elif function.name == 'glUnmapBufferOES': print r' glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);' elif function.name == 'glUnmapNamedBufferEXT': print r' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapObjectBufferATI': # TODO pass else: assert False print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' } else {' print r' retrace::warning(call) << "no current context\n";' print r' }' if function.name in ('glBindProgramPipeline', 'glBindProgramPipelineEXT'): # Note if glBindProgramPipeline has ever been called print r' if (pipeline) {' print r' _pipelineHasBeenBound = true;' print r' }' profileDraw = ( function.name in self.draw_array_function_names or function.name in self.draw_elements_function_names or function.name in self.draw_indirect_function_names or function.name in self.misc_draw_function_names or function.name == 'glBegin' ) if function.name in ('glUseProgram', 'glUseProgramObjectARB'): print r' if (glretrace::currentContext) {' print r' glretrace::currentContext->activeProgram = call.arg(0).toUInt();' print r' }' # Only profile if not inside a list as the queries get inserted into list if function.name == 'glNewList': print r' glretrace::insideList = true;' if function.name == 'glEndList': print r' glretrace::insideList = false;' if function.name != 'glEnd': print r' if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::beginProfile(call, true);' else: print r' glretrace::beginProfile(call, false);' print r' }' if function.name == 'glCreateShaderProgramv': # When dumping state, break down glCreateShaderProgramv so that the # shader source can be recovered. print r' if (retrace::dumpingState) {' print r' GLuint _shader = glCreateShader(type);' print r' if (_shader) {' print r' glShaderSource(_shader, count, strings, NULL);' print r' glCompileShader(_shader);' print r' const GLuint _program = glCreateProgram();' print r' if (_program) {' print r' GLint compiled = GL_FALSE;' print r' glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);' print r' glProgramParameteri(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);' print r' if (compiled) {' print r' glAttachShader(_program, _shader);' print r' glLinkProgram(_program);' print r' //glDetachShader(_program, _shader);' print r' }' print r' //append-shader-info-log-to-program-info-log' print r' }' print r' //glDeleteShader(_shader);' print r' _result = _program;' print r' } else {' print r' _result = 0;' print r' }' print r' } else {' Retracer.invokeFunction(self, function) print r' }' else: Retracer.invokeFunction(self, function) if function.name == "glBegin": print ' glretrace::insideGlBeginEnd = true;' print r' if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::endProfile(call, true);' else: print r' glretrace::endProfile(call, false);' print r' }' # Error checking if function.name.startswith('gl'): # glGetError is not allowed inside glBegin/glEnd print ' if (retrace::debug && !glretrace::insideGlBeginEnd) {' print ' glretrace::checkGlError(call);' if function.name in ('glProgramStringARB', 'glProgramStringNV'): print r' GLint error_position = -1;' print r' glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);' print r' if (error_position != -1) {' print r' const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);' print r' retrace::warning(call) << error_string << "\n";' print r' }' if function.name == 'glCompileShader': print r' GLint compile_status = 0;' print r' glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);' print r' if (!compile_status) {' print r' GLint info_log_length = 0;' print r' glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in ('glLinkProgram', 'glCreateShaderProgramv', 'glCreateShaderProgramEXT'): if function.name != 'glLinkProgram': print r' GLuint program = _result;' print r' GLint link_status = 0;' print r' glGetProgramiv(program, GL_LINK_STATUS, &link_status);' print r' if (!link_status) {' print r' GLint info_log_length = 0;' print r' glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetProgramInfoLog(program, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glCompileShaderARB': print r' GLint compile_status = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);' print r' if (!compile_status) {' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glLinkProgramARB': print r' GLint link_status = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);' print r' if (!link_status) {' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in self.map_function_names: print r' if (!_result) {' print r' retrace::warning(call) << "failed to map buffer\n";' print r' }' if function.name in self.unmap_function_names and function.type is not stdapi.Void: print r' if (!_result) {' print r' retrace::warning(call) << "failed to unmap buffer\n";' print r' }' if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_result != _origResult) {' print r' retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";' print r' }' if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_origResult == GL_FRAMEBUFFER_COMPLETE &&' print r' _result != GL_FRAMEBUFFER_COMPLETE) {' print r' retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";' print r' }' print ' }' # Query the buffer length for whole buffer mappings if function.name in self.map_function_names: if 'length' in function.argNames(): assert 'BufferRange' in function.name else: assert 'BufferRange' not in function.name print r' GLint length = 0;' if function.name in ('glMapBuffer', 'glMapBufferOES'): print r' glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapBufferARB': print r' glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);' elif function.name == 'glMapNamedBufferEXT': print r' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapObjectBufferATI': print r' glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);' else: assert False
def invokeFunction(self, function): # Infer the drawable size from GL calls if function.name == "glViewport": print ' glretrace::updateDrawable(x + width, y + height);' if function.name == "glViewportArray": # We are concerned about drawables so only care for the first viewport print ' if (first == 0 && count > 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedf": print ' if (index == 0) {' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedfv": print ' if (index == 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'): # Some applications do all their rendering in a framebuffer, and # then just blit to the drawable without ever calling glViewport. print ' glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));' if function.name == "glEnd": print ' glretrace::insideGlBeginEnd = false;' if function.name.startswith('gl') and not function.name.startswith('glX'): print r' if (!glretrace::context && !glretrace::benchmark && !retrace::profiling) {' print r' retrace::warning(call) << "no current context\n";' print r' }' if function.name == 'memcpy': print ' if (!dest || !src || !n) return;' # Destroy the buffer mapping if function.name in self.unmap_function_names: print r' GLvoid *ptr = NULL;' if function.name == 'glUnmapBuffer': print r' glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapBufferARB': print r' glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);' elif function.name == 'glUnmapBufferOES': print r' glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);' elif function.name == 'glUnmapNamedBufferEXT': print r' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapObjectBufferATI': # TODO pass else: assert False print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' } else {' print r' retrace::warning(call) << "no current context\n";' print r' }' Retracer.invokeFunction(self, function) # Error checking if function.name == "glBegin": print ' glretrace::insideGlBeginEnd = true;' elif function.name.startswith('gl'): # glGetError is not allowed inside glBegin/glEnd print ' if (!glretrace::benchmark && !retrace::profiling && !glretrace::insideGlBeginEnd) {' print ' glretrace::checkGlError(call);' if function.name in ('glProgramStringARB', 'glProgramStringNV'): print r' GLint error_position = -1;' print r' glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);' print r' if (error_position != -1) {' print r' const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);' print r' retrace::warning(call) << error_string << "\n";' print r' }' if function.name == 'glCompileShader': print r' GLint compile_status = 0;' print r' glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);' print r' if (!compile_status) {' print r' GLint info_log_length = 0;' print r' glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glLinkProgram': print r' GLint link_status = 0;' print r' glGetProgramiv(program, GL_LINK_STATUS, &link_status);' print r' if (!link_status) {' print r' GLint info_log_length = 0;' print r' glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetProgramInfoLog(program, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glCompileShaderARB': print r' GLint compile_status = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);' print r' if (!compile_status) {' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glLinkProgramARB': print r' GLint link_status = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);' print r' if (!link_status) {' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in self.map_function_names: print r' if (!__result) {' print r' retrace::warning(call) << "failed to map buffer\n";' print r' }' if function.name in self.unmap_function_names and function.type is not stdapi.Void: print r' if (!__result) {' print r' retrace::warning(call) << "failed to unmap buffer\n";' print r' }' if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'): print r' GLint __orig_result = call.ret->toSInt();' print r' if (__result != __orig_result) {' print r' retrace::warning(call) << "vertex attrib location mismatch " << __orig_result << " -> " << __result << "\n";' print r' }' if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'): print r' GLint __orig_result = call.ret->toSInt();' print r' if (__orig_result == GL_FRAMEBUFFER_COMPLETE &&' print r' __result != GL_FRAMEBUFFER_COMPLETE) {' print r' retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(__result) << ")\n";' print r' }' print ' }' # Query the buffer length for whole buffer mappings if function.name in self.map_function_names: if 'length' in function.argNames(): assert 'BufferRange' in function.name else: assert 'BufferRange' not in function.name print r' GLint length = 0;' if function.name in ('glMapBuffer', 'glMapBufferOES'): print r' glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapBufferARB': print r' glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);' elif function.name == 'glMapNamedBufferEXT': print r' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapObjectBufferATI': print r' glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);' else: assert False
def invokeFunction(self, function): # Infer the drawable size from GL calls if function.name == "glViewport": print ' glretrace::updateDrawable(x + width, y + height);' if function.name == "glViewportArrayv": # We are concerned about drawables so only care for the first viewport print ' if (first == 0 && count > 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedf": print ' if (index == 0) {' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedfv": print ' if (index == 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'): # Some applications do all their rendering in a framebuffer, and # then just blit to the drawable without ever calling glViewport. print ' glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));' if function.name == "glEnd": print r' if (currentContext) {' print r' currentContext->insideBeginEnd = false;' print r' }' if function.name == 'memcpy': print ' if (!dest || !src || !n) return;' # Skip glEnable/Disable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) as we don't # faithfully set the CONTEXT_DEBUG_BIT_ARB flags on context creation. if function.name in ('glEnable', 'glDisable'): print ' if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) return;' # Destroy the buffer mapping if self.unmap_function_regex.match(function.name): print r' GLvoid *ptr = NULL;' if function.name == 'glUnmapBuffer': print r' glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapBufferARB': print r' glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);' elif function.name == 'glUnmapBufferOES': print r' glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);' elif function.name == 'glUnmapNamedBuffer': print r' glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapNamedBufferEXT': print r' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapObjectBufferATI': # TODO pass else: assert False print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' } else {' print r' retrace::warning(call) << "failed to get mapped pointer\n";' print r' }' # Implicit destruction of buffer mappings # TODO: handle BufferData variants # TODO: don't rely on GL_ARB_direct_state_access if function.name in ('glDeleteBuffers', 'glDeleteBuffersARB'): print r' if (currentContext->features().ARB_direct_state_access) {' print r' for (GLsizei i = 0; i < n; ++i) {' print r' GLvoid *ptr = nullptr;' print r' glGetNamedBufferPointerv(buffers[i], GL_BUFFER_MAP_POINTER, &ptr);' print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' }' print r' }' print r' }' if function.name.startswith('glCopyImageSubData'): print r' if (srcTarget == GL_RENDERBUFFER || dstTarget == GL_RENDERBUFFER) {' print r' retrace::warning(call) << " renderbuffer targets unsupported (https://github.com/apitrace/apitrace/issues/404)\n";' print r' }' is_draw_arrays = self.draw_arrays_function_regex.match(function.name) is not None is_draw_elements = self.draw_elements_function_regex.match(function.name) is not None is_misc_draw = self.misc_draw_function_regex.match(function.name) is not None profileDraw = ( is_draw_arrays or is_draw_elements or is_misc_draw or function.name == 'glBegin' or function.name.startswith('glDispatchCompute') ) # Keep track of current program/pipeline if function.name in ('glUseProgram', 'glUseProgramObjectARB'): print r' if (currentContext) {' print r' currentContext->currentUserProgram = call.arg(0).toUInt();' print r' currentContext->currentProgram = %s;' % function.args[0].name print r' }' if function.name in ('glBindProgramPipeline', 'glBindProgramPipelineEXT'): print r' if (currentContext) {' print r' currentContext->currentPipeline = %s;' % function.args[0].name print r' }' # Only profile if not inside a list as the queries get inserted into list if function.name == 'glNewList': print r' if (currentContext) {' print r' currentContext->insideList = true;' print r' }' if function.name == 'glEndList': print r' if (currentContext) {' print r' currentContext->insideList = false;' print r' }' if function.name == 'glBegin' or \ is_draw_arrays or \ is_draw_elements or \ function.name.startswith('glBeginTransformFeedback'): print r' if (retrace::debug) {' print r' _validateActiveProgram(call);' print r' }' if function.name != 'glEnd': print r' if (currentContext && !currentContext->insideList && !currentContext->insideBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::beginProfile(call, true);' else: print r' glretrace::beginProfile(call, false);' print r' }' if function.name in ('glCreateShaderProgramv', 'glCreateShaderProgramEXT', 'glCreateShaderProgramvEXT'): # When dumping state, break down glCreateShaderProgram* so that the # shader source can be recovered. print r' if (retrace::dumpingState) {' print r' GLuint _shader = glCreateShader(type);' print r' if (_shader) {' if not function.name.startswith('glCreateShaderProgramv'): print r' GLsizei count = 1;' print r' const GLchar **strings = &string;' print r' glShaderSource(_shader, count, strings, NULL);' print r' glCompileShader(_shader);' print r' const GLuint _program = glCreateProgram();' print r' if (_program) {' print r' GLint compiled = GL_FALSE;' print r' glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);' if function.name == 'glCreateShaderProgramvEXT': print r' glProgramParameteriEXT(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);' else: print r' glProgramParameteri(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);' print r' if (compiled) {' print r' glAttachShader(_program, _shader);' print r' glLinkProgram(_program);' print r' if (false) glDetachShader(_program, _shader);' print r' }' print r' // TODO: append shader info log to program info log' print r' }' print r' glDeleteShader(_shader);' print r' _result = _program;' print r' } else {' print r' _result = 0;' print r' }' print r' } else {' Retracer.invokeFunction(self, function) print r' }' elif function.name in ('glDetachShader', 'glDetachObjectARB'): print r' if (!retrace::dumpingState) {' Retracer.invokeFunction(self, function) print r' }' elif function.name == 'glClientWaitSync': print r' _result = glretrace::clientWaitSync(call, sync, flags, timeout);' print r' (void)_result;' elif function.name == 'glGetSynciv': print r' if (pname == GL_SYNC_STATUS &&' print r' bufSize >= 1 &&' print r' values != NULL &&' print r' call.arg(4)[0].toSInt() == GL_SIGNALED) {' print r' // Fence was signalled, so ensure it happened here' print r' glretrace::blockOnFence(call, sync, GL_SYNC_FLUSH_COMMANDS_BIT);' print r' (void)length;' print r' }' else: Retracer.invokeFunction(self, function) # Ensure this context flushes before switching to another thread to # prevent deadlock. # TODO: Defer flushing until another thread actually invokes # ClientWaitSync. if function.name.startswith("glFenceSync"): print ' if (currentContext) {' print ' currentContext->needsFlush = true;' print ' }' if function.name in ("glFlush", "glFinish"): print ' if (currentContext) {' print ' currentContext->needsFlush = false;' print ' }' if function.name == "glBegin": print ' if (currentContext) {' print ' currentContext->insideBeginEnd = true;' print ' }' print r' if (currentContext && !currentContext->insideList && !currentContext->insideBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::endProfile(call, true);' else: print r' glretrace::endProfile(call, false);' print r' }' # Error checking if function.name.startswith('gl'): # glGetError is not allowed inside glBegin/glEnd print ' if (retrace::debug && currentContext && !currentContext->insideBeginEnd) {' print ' glretrace::checkGlError(call);' if function.name in ('glProgramStringARB', 'glLoadProgramNV'): print r' GLint error_position = -1;' print r' glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);' print r' if (error_position != -1) {' print r' const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);' print r' retrace::warning(call) << "error in position " << error_position << ": " << error_string << "\n";' print r' }' if function.name == 'glCompileShader': print r' GLint compile_status = 0;' print r' glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);' print r' if (!compile_status) {' print r' retrace::warning(call) << "compilation failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in ('glLinkProgram', 'glCreateShaderProgramv', 'glCreateShaderProgramEXT', 'glCreateShaderProgramvEXT', 'glProgramBinary', 'glProgramBinaryOES'): if function.name.startswith('glCreateShaderProgram'): print r' GLuint program = _result;' print r' GLint link_status = 0;' print r' glGetProgramiv(program, GL_LINK_STATUS, &link_status);' print r' if (!link_status) {' print r' retrace::warning(call) << "link failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetProgramInfoLog(program, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glCompileShaderARB': print r' GLint compile_status = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);' print r' if (!compile_status) {' print r' retrace::warning(call) << "compilation failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glLinkProgramARB': print r' GLint link_status = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);' print r' if (!link_status) {' print r' retrace::warning(call) << "link failed\n";' print r' }' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' if (info_log_length > 1) {' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if self.map_function_regex.match(function.name): print r' if (!_result) {' print r' retrace::warning(call) << "failed to map buffer\n";' print r' }' if self.unmap_function_regex.match(function.name) and function.type is not stdapi.Void: print r' if (!_result) {' print r' retrace::warning(call) << "failed to unmap buffer\n";' print r' }' if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_result != _origResult) {' print r' retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";' print r' }' if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatus', 'glCheckNamedFramebufferStatusEXT'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_origResult == GL_FRAMEBUFFER_COMPLETE &&' print r' _result != GL_FRAMEBUFFER_COMPLETE) {' print r' retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";' print r' }' print ' }' # Query the buffer length for whole buffer mappings if self.map_function_regex.match(function.name): if 'length' in function.argNames(): assert 'BufferRange' in function.name else: assert 'BufferRange' not in function.name print r' GLint length = 0;' if function.name in ('glMapBuffer', 'glMapBufferOES'): print r' glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapBufferARB': print r' glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);' elif function.name == 'glMapNamedBuffer': print r' glGetNamedBufferParameteriv(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapNamedBufferEXT': print r' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapObjectBufferATI': print r' glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);' else: assert False
def invokeFunction(self, function): # Infer the drawable size from GL calls if function.name == "glViewport": print ' glretrace::updateDrawable(x + width, y + height);' if function.name == "glViewportArray": # We are concerned about drawables so only care for the first viewport print ' if (first == 0 && count > 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedf": print ' if (index == 0) {' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name == "glViewportIndexedfv": print ' if (index == 0) {' print ' GLfloat x = v[0], y = v[1], w = v[2], h = v[3];' print ' glretrace::updateDrawable(x + w, y + h);' print ' }' if function.name in ('glBlitFramebuffer', 'glBlitFramebufferEXT'): # Some applications do all their rendering in a framebuffer, and # then just blit to the drawable without ever calling glViewport. print ' glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));' if function.name == "glEnd": print ' glretrace::insideGlBeginEnd = false;' if function.name.startswith('gl') and not function.name.startswith('glX'): print r' if (retrace::debug && !glretrace::getCurrentContext()) {' print r' retrace::warning(call) << "no current context\n";' print r' }' if function.name == 'memcpy': print ' if (!dest || !src || !n) return;' # Skip glEnable/Disable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) as we don't # faithfully set the CONTEXT_DEBUG_BIT_ARB flags on context creation. if function.name in ('glEnable', 'glDisable'): print ' if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) return;' # Destroy the buffer mapping if function.name in self.unmap_function_names: print r' GLvoid *ptr = NULL;' if function.name == 'glUnmapBuffer': print r' glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapBufferARB': print r' glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);' elif function.name == 'glUnmapBufferOES': print r' glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);' elif function.name == 'glUnmapNamedBufferEXT': print r' glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);' elif function.name == 'glUnmapObjectBufferATI': # TODO pass else: assert False print r' if (ptr) {' print r' retrace::delRegionByPointer(ptr);' print r' } else {' print r' retrace::warning(call) << "no current context\n";' print r' }' if function.name in ('glBindProgramPipeline', 'glBindProgramPipelineEXT'): # Note if glBindProgramPipeline has ever been called print r' if (pipeline) {' print r' _pipelineHasBeenBound = true;' print r' }' profileDraw = ( function.name in self.draw_array_function_names or function.name in self.draw_elements_function_names or function.name in self.draw_indirect_function_names or function.name in self.misc_draw_function_names or function.name == 'glBegin' ) if function.name in ('glUseProgram', 'glUseProgramObjectARB'): print r' glretrace::Context *currentContext = glretrace::getCurrentContext();' print r' if (currentContext) {' print r' currentContext->activeProgram = call.arg(0).toUInt();' print r' }' # Only profile if not inside a list as the queries get inserted into list if function.name == 'glNewList': print r' glretrace::insideList = true;' if function.name == 'glEndList': print r' glretrace::insideList = false;' if function.name != 'glEnd': print r' if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::beginProfile(call, true);' else: print r' glretrace::beginProfile(call, false);' print r' }' if function.name == 'glCreateShaderProgramv': # When dumping state, break down glCreateShaderProgramv so that the # shader source can be recovered. print r' if (retrace::dumpingState) {' print r' GLuint _shader = glCreateShader(type);' print r' if (_shader) {' print r' glShaderSource(_shader, count, strings, NULL);' print r' glCompileShader(_shader);' print r' const GLuint _program = glCreateProgram();' print r' if (_program) {' print r' GLint compiled = GL_FALSE;' print r' glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);' print r' glProgramParameteri(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);' print r' if (compiled) {' print r' glAttachShader(_program, _shader);' print r' glLinkProgram(_program);' print r' //glDetachShader(_program, _shader);' print r' }' print r' //append-shader-info-log-to-program-info-log' print r' }' print r' //glDeleteShader(_shader);' print r' _result = _program;' print r' } else {' print r' _result = 0;' print r' }' print r' } else {' Retracer.invokeFunction(self, function) print r' }' else: Retracer.invokeFunction(self, function) if function.name == "glBegin": print ' glretrace::insideGlBeginEnd = true;' print r' if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {' if profileDraw: print r' glretrace::endProfile(call, true);' else: print r' glretrace::endProfile(call, false);' print r' }' # Error checking if function.name.startswith('gl'): # glGetError is not allowed inside glBegin/glEnd print ' if (retrace::debug && !glretrace::insideGlBeginEnd && glretrace::getCurrentContext()) {' print ' glretrace::checkGlError(call);' if function.name in ('glProgramStringARB', 'glProgramStringNV'): print r' GLint error_position = -1;' print r' glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);' print r' if (error_position != -1) {' print r' const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);' print r' retrace::warning(call) << error_string << "\n";' print r' }' if function.name == 'glCompileShader': print r' GLint compile_status = 0;' print r' glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);' print r' if (!compile_status) {' print r' GLint info_log_length = 0;' print r' glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in ('glLinkProgram', 'glCreateShaderProgramv', 'glCreateShaderProgramEXT'): if function.name != 'glLinkProgram': print r' GLuint program = _result;' print r' GLint link_status = 0;' print r' glGetProgramiv(program, GL_LINK_STATUS, &link_status);' print r' if (!link_status) {' print r' GLint info_log_length = 0;' print r' glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetProgramInfoLog(program, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glCompileShaderARB': print r' GLint compile_status = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);' print r' if (!compile_status) {' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name == 'glLinkProgramARB': print r' GLint link_status = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);' print r' if (!link_status) {' print r' GLint info_log_length = 0;' print r' glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);' print r' GLchar *infoLog = new GLchar[info_log_length];' print r' glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);' print r' retrace::warning(call) << infoLog << "\n";' print r' delete [] infoLog;' print r' }' if function.name in self.map_function_names: print r' if (!_result) {' print r' retrace::warning(call) << "failed to map buffer\n";' print r' }' if function.name in self.unmap_function_names and function.type is not stdapi.Void: print r' if (!_result) {' print r' retrace::warning(call) << "failed to unmap buffer\n";' print r' }' if function.name in ('glGetAttribLocation', 'glGetAttribLocationARB'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_result != _origResult) {' print r' retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";' print r' }' if function.name in ('glCheckFramebufferStatus', 'glCheckFramebufferStatusEXT', 'glCheckNamedFramebufferStatusEXT'): print r' GLint _origResult = call.ret->toSInt();' print r' if (_origResult == GL_FRAMEBUFFER_COMPLETE &&' print r' _result != GL_FRAMEBUFFER_COMPLETE) {' print r' retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";' print r' }' print ' }' # Query the buffer length for whole buffer mappings if function.name in self.map_function_names: if 'length' in function.argNames(): assert 'BufferRange' in function.name else: assert 'BufferRange' not in function.name print r' GLint length = 0;' if function.name in ('glMapBuffer', 'glMapBufferOES'): print r' glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapBufferARB': print r' glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);' elif function.name == 'glMapNamedBufferEXT': print r' glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);' elif function.name == 'glMapObjectBufferATI': print r' glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);' else: assert False
def invokeFunction(self, function): # Infer the drawable size from GL calls if function.name == "glViewport": print " glretrace::updateDrawable(x + width, y + height);" if function.name == "glViewportArray": # We are concerned about drawables so only care for the first viewport print " if (first == 0 && count > 0) {" print " GLfloat x = v[0], y = v[1], w = v[2], h = v[3];" print " glretrace::updateDrawable(x + w, y + h);" print " }" if function.name == "glViewportIndexedf": print " if (index == 0) {" print " glretrace::updateDrawable(x + w, y + h);" print " }" if function.name == "glViewportIndexedfv": print " if (index == 0) {" print " GLfloat x = v[0], y = v[1], w = v[2], h = v[3];" print " glretrace::updateDrawable(x + w, y + h);" print " }" if function.name in ("glBlitFramebuffer", "glBlitFramebufferEXT"): # Some applications do all their rendering in a framebuffer, and # then just blit to the drawable without ever calling glViewport. print " glretrace::updateDrawable(std::max(dstX0, dstX1), std::max(dstY0, dstY1));" if function.name == "glEnd": print " glretrace::insideGlBeginEnd = false;" if function.name.startswith("gl") and not function.name.startswith("glX"): print r" if (retrace::debug && !glretrace::getCurrentContext()) {" print r' retrace::warning(call) << "no current context\n";' print r" }" if function.name == "memcpy": print " if (!dest || !src || !n) return;" # Skip glEnable/Disable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) as we don't # faithfully set the CONTEXT_DEBUG_BIT_ARB flags on context creation. if function.name in ("glEnable", "glDisable"): print " if (cap == GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB) return;" # Destroy the buffer mapping if self.unmap_function_regex.match(function.name): print r" GLvoid *ptr = NULL;" if function.name == "glUnmapBuffer": print r" glGetBufferPointerv(target, GL_BUFFER_MAP_POINTER, &ptr);" elif function.name == "glUnmapBufferARB": print r" glGetBufferPointervARB(target, GL_BUFFER_MAP_POINTER_ARB, &ptr);" elif function.name == "glUnmapBufferOES": print r" glGetBufferPointervOES(target, GL_BUFFER_MAP_POINTER_OES, &ptr);" elif function.name == "glUnmapNamedBuffer": print r" glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &ptr);" elif function.name == "glUnmapNamedBuffer": print r" glGetNamedBufferPointerv(buffer, GL_BUFFER_MAP_POINTER, &ptr);" elif function.name == "glUnmapNamedBufferEXT": print r" glGetNamedBufferPointervEXT(buffer, GL_BUFFER_MAP_POINTER, &ptr);" elif function.name == "glUnmapObjectBufferATI": # TODO pass else: assert False print r" if (ptr) {" print r" retrace::delRegionByPointer(ptr);" print r" } else {" print r' retrace::warning(call) << "failed to get mapped pointer\n";' print r" }" if function.name in ("glBindProgramPipeline", "glBindProgramPipelineEXT"): # Note if glBindProgramPipeline has ever been called print r" if (pipeline) {" print r" _pipelineHasBeenBound = true;" print r" }" is_draw_arrays = self.draw_arrays_function_regex.match(function.name) is not None is_draw_elements = self.draw_elements_function_regex.match(function.name) is not None is_misc_draw = self.misc_draw_function_regex.match(function.name) is not None profileDraw = is_draw_arrays or is_draw_elements or is_misc_draw or function.name == "glBegin" # Keep track of active program for call lists if function.name in ("glUseProgram", "glUseProgramObjectARB"): print r" glretrace::Context *currentContext = glretrace::getCurrentContext();" print r" if (currentContext) {" print r" currentContext->activeProgram = call.arg(0).toUInt();" print r" }" # Only profile if not inside a list as the queries get inserted into list if function.name == "glNewList": print r" glretrace::insideList = true;" if function.name == "glEndList": print r" glretrace::insideList = false;" if ( function.name == "glBegin" or is_draw_arrays or is_draw_elements or function.name.startswith("glBeginTransformFeedback") ): print r" if (retrace::debug && !glretrace::insideGlBeginEnd && glretrace::getCurrentContext()) {" print r" _validateActiveProgram(call);" print r" }" if function.name != "glEnd": print r" if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {" if profileDraw: print r" glretrace::beginProfile(call, true);" else: print r" glretrace::beginProfile(call, false);" print r" }" if function.name in ("glCreateShaderProgramv", "glCreateShaderProgramEXT", "glCreateShaderProgramvEXT"): # When dumping state, break down glCreateShaderProgram* so that the # shader source can be recovered. print r" if (retrace::dumpingState) {" print r" GLuint _shader = glCreateShader(type);" print r" if (_shader) {" if not function.name.startswith("glCreateShaderProgramv"): print r" GLsizei count = 1;" print r" const GLchar **strings = &string;" print r" glShaderSource(_shader, count, strings, NULL);" print r" glCompileShader(_shader);" print r" const GLuint _program = glCreateProgram();" print r" if (_program) {" print r" GLint compiled = GL_FALSE;" print r" glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);" if function.name == "glCreateShaderProgramvEXT": print r" glProgramParameteriEXT(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);" else: print r" glProgramParameteri(_program, GL_PROGRAM_SEPARABLE, GL_TRUE);" print r" if (compiled) {" print r" glAttachShader(_program, _shader);" print r" glLinkProgram(_program);" print r" if (false) glDetachShader(_program, _shader);" print r" }" print r" // TODO: append shader info log to program info log" print r" }" print r" glDeleteShader(_shader);" print r" _result = _program;" print r" } else {" print r" _result = 0;" print r" }" print r" } else {" Retracer.invokeFunction(self, function) print r" }" elif function.name in ("glDetachShader", "glDetachObjectARB"): print r" if (!retrace::dumpingState) {" Retracer.invokeFunction(self, function) print r" }" elif function.name == "glClientWaitSync": print r" _result = glretrace::clientWaitSync(call, sync, flags, timeout);" print r" (void)_result;" elif function.name == "glGetSynciv": print r" if (pname == GL_SYNC_STATUS &&" print r" bufSize >= 1 &&" print r" values != NULL &&" print r" call.arg(4)[0].toSInt() == GL_SIGNALED) {" print r" // Fence was signalled, so ensure it happened here" print r" glretrace::blockOnFence(call, sync, GL_SYNC_FLUSH_COMMANDS_BIT);" print r" (void)length;" print r" }" else: Retracer.invokeFunction(self, function) if function.name == "glBegin": print " glretrace::insideGlBeginEnd = true;" print r" if (!glretrace::insideList && !glretrace::insideGlBeginEnd && retrace::profiling) {" if profileDraw: print r" glretrace::endProfile(call, true);" else: print r" glretrace::endProfile(call, false);" print r" }" # Error checking if function.name.startswith("gl"): # glGetError is not allowed inside glBegin/glEnd print " if (retrace::debug && !glretrace::insideGlBeginEnd && glretrace::getCurrentContext()) {" print " glretrace::checkGlError(call);" if function.name in ("glProgramStringARB", "glLoadProgramNV"): print r" GLint error_position = -1;" print r" glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_position);" print r" if (error_position != -1) {" print r" const char *error_string = (const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB);" print r' retrace::warning(call) << "error in position " << error_position << ": " << error_string << "\n";' print r" }" if function.name == "glCompileShader": print r" GLint compile_status = 0;" print r" glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);" print r" if (!compile_status) {" print r' retrace::warning(call) << "compilation failed\n";' print r" }" print r" GLint info_log_length = 0;" print r" glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);" print r" if (info_log_length > 1) {" print r" GLchar *infoLog = new GLchar[info_log_length];" print r" glGetShaderInfoLog(shader, info_log_length, NULL, infoLog);" print r' retrace::warning(call) << infoLog << "\n";' print r" delete [] infoLog;" print r" }" if function.name in ( "glLinkProgram", "glCreateShaderProgramv", "glCreateShaderProgramEXT", "glCreateShaderProgramvEXT", "glProgramBinary", "glProgramBinaryOES", ): if function.name.startswith("glCreateShaderProgram"): print r" GLuint program = _result;" print r" GLint link_status = 0;" print r" glGetProgramiv(program, GL_LINK_STATUS, &link_status);" print r" if (!link_status) {" print r' retrace::warning(call) << "link failed\n";' print r" }" print r" GLint info_log_length = 0;" print r" glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_log_length);" print r" if (info_log_length > 1) {" print r" GLchar *infoLog = new GLchar[info_log_length];" print r" glGetProgramInfoLog(program, info_log_length, NULL, infoLog);" print r' retrace::warning(call) << infoLog << "\n";' print r" delete [] infoLog;" print r" }" if function.name == "glCompileShaderARB": print r" GLint compile_status = 0;" print r" glGetObjectParameterivARB(shaderObj, GL_OBJECT_COMPILE_STATUS_ARB, &compile_status);" print r" if (!compile_status) {" print r' retrace::warning(call) << "compilation failed\n";' print r" }" print r" GLint info_log_length = 0;" print r" glGetObjectParameterivARB(shaderObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);" print r" if (info_log_length > 1) {" print r" GLchar *infoLog = new GLchar[info_log_length];" print r" glGetInfoLogARB(shaderObj, info_log_length, NULL, infoLog);" print r' retrace::warning(call) << infoLog << "\n";' print r" delete [] infoLog;" print r" }" if function.name == "glLinkProgramARB": print r" GLint link_status = 0;" print r" glGetObjectParameterivARB(programObj, GL_OBJECT_LINK_STATUS_ARB, &link_status);" print r" if (!link_status) {" print r' retrace::warning(call) << "link failed\n";' print r" }" print r" GLint info_log_length = 0;" print r" glGetObjectParameterivARB(programObj, GL_OBJECT_INFO_LOG_LENGTH_ARB, &info_log_length);" print r" if (info_log_length > 1) {" print r" GLchar *infoLog = new GLchar[info_log_length];" print r" glGetInfoLogARB(programObj, info_log_length, NULL, infoLog);" print r' retrace::warning(call) << infoLog << "\n";' print r" delete [] infoLog;" print r" }" if self.map_function_regex.match(function.name): print r" if (!_result) {" print r' retrace::warning(call) << "failed to map buffer\n";' print r" }" if self.unmap_function_regex.match(function.name) and function.type is not stdapi.Void: print r" if (!_result) {" print r' retrace::warning(call) << "failed to unmap buffer\n";' print r" }" if function.name in ("glGetAttribLocation", "glGetAttribLocationARB"): print r" GLint _origResult = call.ret->toSInt();" print r" if (_result != _origResult) {" print r' retrace::warning(call) << "vertex attrib location mismatch " << _origResult << " -> " << _result << "\n";' print r" }" if function.name in ( "glCheckFramebufferStatus", "glCheckFramebufferStatusEXT", "glCheckNamedFramebufferStatus", "glCheckNamedFramebufferStatusEXT", ): print r" GLint _origResult = call.ret->toSInt();" print r" if (_origResult == GL_FRAMEBUFFER_COMPLETE &&" print r" _result != GL_FRAMEBUFFER_COMPLETE) {" print r' retrace::warning(call) << "incomplete framebuffer (" << glstate::enumToString(_result) << ")\n";' print r" }" print " }" # Query the buffer length for whole buffer mappings if self.map_function_regex.match(function.name): if "length" in function.argNames(): assert "BufferRange" in function.name else: assert "BufferRange" not in function.name print r" GLint length = 0;" if function.name in ("glMapBuffer", "glMapBufferOES"): print r" glGetBufferParameteriv(target, GL_BUFFER_SIZE, &length);" elif function.name == "glMapBufferARB": print r" glGetBufferParameterivARB(target, GL_BUFFER_SIZE_ARB, &length);" elif function.name == "glMapNamedBuffer": print r" glGetNamedBufferParameteriv(buffer, GL_BUFFER_SIZE, &length);" elif function.name == "glMapNamedBufferEXT": print r" glGetNamedBufferParameterivEXT(buffer, GL_BUFFER_SIZE, &length);" elif function.name == "glMapObjectBufferATI": print r" glGetObjectBufferivATI(buffer, GL_OBJECT_BUFFER_SIZE_ATI, &length);" else: assert False