#include #include #include #include #include #include #include namespace mbgl { namespace gl { ExtensionFunction BindVertexArray({ {"GL_ARB_vertex_array_object", "glBindVertexArray"}, {"GL_OES_vertex_array_object", "glBindVertexArrayOES"}, {"GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE"} }); ExtensionFunction DeleteVertexArrays({ {"GL_ARB_vertex_array_object", "glDeleteVertexArrays"}, {"GL_OES_vertex_array_object", "glDeleteVertexArraysOES"}, {"GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE"} }); ExtensionFunction GenVertexArrays({ {"GL_ARB_vertex_array_object", "glGenVertexArrays"}, {"GL_OES_vertex_array_object", "glGenVertexArraysOES"}, {"GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE"} }); std::vector& ExtensionFunctionBase::functions() { static std::vector functions; return functions; } static std::once_flag initializeExtensionsOnce; void InitializeExtensions(glProc (*getProcAddress)(const char *)) { std::call_once(initializeExtensionsOnce, [getProcAddress] { const char * extensionsPtr = reinterpret_cast( MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS))); if (!extensionsPtr) return; const std::string extensions = extensionsPtr; for (auto fn : ExtensionFunctionBase::functions()) { for (auto probe : fn->probes) { if (extensions.find(probe.first) != std::string::npos) { #ifdef GL_TRACK fn->foundName = probe.second; #endif fn->ptr = getProcAddress(probe.second); break; } } } }); } void checkError(const char *cmd, const char *file, int line) { const GLenum err = glGetError(); if (err != GL_NO_ERROR) { const char *error = nullptr; switch (err) { case GL_INVALID_ENUM: error = "INVALID_ENUM"; break; case GL_INVALID_VALUE: error = "INVALID_VALUE"; break; case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break; case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break; case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break; #ifdef GL_STACK_UNDERFLOW case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break; #endif #ifdef GL_STACK_OVERFLOW case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break; #endif default: error = "(unknown)"; break; } throw ::mbgl::gl::Error(err, std::string(cmd) + ": Error GL_" + error + " - " + file + ":" + util::toString(line)); } } } // namespace gl } // namespace mbgl #ifdef GL_TRACK #undef glBindTexture #undef glDeleteTextures #undef glTexImage2D #undef glClear #undef glShaderSource #undef glBufferData #undef glBindBuffer #undef glDeleteBuffers #undef glBufferData static unsigned int currentUsedBytes = 0; static GLint currentBoundTexture = 0; static std::map bindingToSizeMap; static GLuint currentArrayBuffer = 0; static GLuint currentElementArrayBuffer = 0; static std::map bufferBindingToSizeMap; static unsigned int currentUsedBufferBytes = 0; static unsigned int largestAmountUsedSoFar = 0; static std::map vertexArrayToArrayBufferMap; static GLuint currentVertexArray = 0; static std::mutex gDebugMutex; namespace mbgl { namespace gl { void mbx_trapExtension(const char *) { } void mbx_trapExtension(const char *, GLint, const char *) { } void mbx_trapExtension(const char *, GLsizei, GLuint *) { } void mbx_trapExtension(const char *, GLsizei, const GLuint *) { } void mbx_trapExtension(const char *, GLenum, GLenum, GLenum, GLsizei, const GLuint *, GLboolean) { } void mbx_trapExtension(const char *, GLenum, GLuint, GLsizei, const GLchar *) { } void mbx_trapExtension(const char *, GLDEBUGPROC, const void *) { } void mbx_trapExtension(const char *, GLuint, GLuint, GLuint, GLuint, GLint, const char *, const void*) { } void mbx_trapExtension(const char *name, GLuint array) { if(strncasecmp(name, "glBindVertexArray", 17) == 0) { currentVertexArray = array; std::cout << name << ": " << array << std::endl; } } } } void mbx_glBindBuffer(GLenum target, GLuint buffer) { std::unique_lock lock(gDebugMutex); if (target == GL_ARRAY_BUFFER) { currentArrayBuffer = buffer; if (currentVertexArray != 0) { if (vertexArrayToArrayBufferMap.find(currentVertexArray) != vertexArrayToArrayBufferMap.end()) { if (vertexArrayToArrayBufferMap[currentVertexArray] != currentArrayBuffer) { std::cout << "glBindBuffer: ERROR: You are re-binding a VAO to point to a new array buffer. This is almost certainly unintended." << std::endl; } } std::cout << "glBindBuffer: binding VAO " << currentVertexArray << " to array buffer " << currentArrayBuffer << std::endl; vertexArrayToArrayBufferMap[currentVertexArray] = currentArrayBuffer; } } else if (target == GL_ELEMENT_ARRAY_BUFFER) { currentElementArrayBuffer = buffer; } lock.unlock(); glBindBuffer(target, buffer); } void mbx_glDeleteBuffers(GLsizei n, const GLuint * buffers) { std::unique_lock lock(gDebugMutex); for (int i = 0; i < n; ++i) { if (bufferBindingToSizeMap.find(buffers[i]) != bufferBindingToSizeMap.end()) { currentUsedBufferBytes -= bufferBindingToSizeMap[buffers[i]]; std::cout << "GL glDeleteBuffers: " << buffers[i] << " freeing " << bufferBindingToSizeMap[buffers[i]] << " bytes current total " << currentUsedBufferBytes << "\n"; bufferBindingToSizeMap.erase(buffers[i]); } } lock.unlock(); glDeleteBuffers(n, buffers); } void mbx_glBufferData(GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage) { std::unique_lock lock(gDebugMutex); GLuint currentBinding = 0; if (target == GL_ARRAY_BUFFER) { currentBinding = currentArrayBuffer; } else if (target == GL_ELEMENT_ARRAY_BUFFER) { currentBinding = currentElementArrayBuffer; } if (bufferBindingToSizeMap.find(currentBinding) != bufferBindingToSizeMap.end()) { currentUsedBufferBytes -= bufferBindingToSizeMap[currentBinding]; std::cout << "GL glBufferData: " << currentBinding << " freeing " << bufferBindingToSizeMap[currentBinding] << " bytes current total " << currentUsedBufferBytes << "\n"; } bufferBindingToSizeMap[currentBinding] = size; currentUsedBufferBytes += size; if (currentUsedBufferBytes > largestAmountUsedSoFar) { largestAmountUsedSoFar = currentUsedBufferBytes; } std::cout << "GL glBufferData: " << currentBinding << " using " << bufferBindingToSizeMap[currentBinding] << " bytes current total " << currentUsedBufferBytes << " high water mark " << largestAmountUsedSoFar << "\n"; lock.unlock(); glBufferData(target, size, data, usage); } void mbx_glShaderSource(GLuint shader, GLsizei count, const GLchar * const *string, const GLint *length) { //std::cout << "Calling glShaderSource: " << *string << std::endl; glShaderSource(shader, count, const_cast(string), length); } void mbx_glClear(GLbitfield mask) { //std::cout << "Calling glClear" << std::endl; glClear(mask); } void mbx_glBindTexture( GLenum target, GLuint texture) { std::unique_lock lock(gDebugMutex); if (target == GL_TEXTURE_2D) { currentBoundTexture = texture; } lock.unlock(); glBindTexture(target, texture); } void mbx_glDeleteTextures(GLsizei n, const GLuint * textures) { std::unique_lock lock(gDebugMutex); for (int i = 0; i < n; ++i) { if (bindingToSizeMap.find(textures[i]) != bindingToSizeMap.end()) { std::cout << "GL deleteTexture:" << textures[i] << "freeing " << bindingToSizeMap[textures[i]] << " bytes current total " << currentUsedBytes << "\n"; currentUsedBytes -= bindingToSizeMap[textures[i]]; bindingToSizeMap.erase(textures[i]); } } lock.unlock(); glDeleteTextures(n, textures); } void mbx_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid * data) { std::unique_lock lock(gDebugMutex); if (internalformat == GL_RGBA && type == GL_UNSIGNED_BYTE) { if (bindingToSizeMap.find(currentBoundTexture) != bindingToSizeMap.end()) { currentUsedBytes -= bindingToSizeMap[currentBoundTexture]; std::cout << "GL glTexImage2D: " << currentBoundTexture << " freeing " << bindingToSizeMap[currentBoundTexture] << " bytes current total " << currentUsedBytes << "\n"; } bindingToSizeMap[currentBoundTexture] = width * height * 4; currentUsedBytes += bindingToSizeMap[currentBoundTexture]; std::cout << "GL glTexImage2D: " << currentBoundTexture << " freeing " << bindingToSizeMap[currentBoundTexture] << " bytes current total " << currentUsedBytes << "\n"; } lock.unlock(); glTexImage2D(target, level, internalformat, width, height, border, format, type, data); } #endif