diff options
Diffstat (limited to 'src/mbgl/gl/context.cpp')
-rw-r--r-- | src/mbgl/gl/context.cpp | 161 |
1 files changed, 131 insertions, 30 deletions
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 1b4d6fbcb7..cc5aa014ed 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -1,4 +1,3 @@ -#include <mbgl/map/view.hpp> #include <mbgl/gl/context.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/debugging_extension.hpp> @@ -16,6 +15,31 @@ namespace gl { static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch"); static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Byte) == GL_BYTE, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::UnsignedByte) == GL_UNSIGNED_BYTE, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Short) == GL_SHORT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::UnsignedShort) == GL_UNSIGNED_SHORT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Integer) == GL_INT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::UnsignedInteger) == GL_UNSIGNED_INT, "OpenGL type mismatch"); +static_assert(underlying_type(DataType::Float) == GL_FLOAT, "OpenGL type mismatch"); + +#if not MBGL_USE_GLES2 +static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8, "OpenGL type mismatch"); +#else +static_assert(underlying_type(RenderbufferType::RGBA) == GL_RGBA8_OES, "OpenGL type mismatch"); +#endif // MBGL_USE_GLES2 +#if not MBGL_USE_GLES2 +static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8, "OpenGL type mismatch"); +#else +static_assert(underlying_type(RenderbufferType::DepthStencil) == GL_DEPTH24_STENCIL8_OES, "OpenGL type mismatch"); +#endif // MBGL_USE_GLES2 +#if not MBGL_USE_GLES2 +static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT, "OpenGL type mismatch"); +#else +static_assert(underlying_type(RenderbufferType::DepthComponent) == GL_DEPTH_COMPONENT16, "OpenGL type mismatch"); +#endif // MBGL_USE_GLES2 + + static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch"); static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch"); static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch"); @@ -36,12 +60,36 @@ static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch"); static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Float) == GL_FLOAT, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec2) == GL_FLOAT_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec3) == GL_FLOAT_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec4) == GL_FLOAT_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Int) == GL_INT, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec2) == GL_INT_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec3) == GL_INT_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec4) == GL_INT_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Bool) == GL_BOOL, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec2) == GL_BOOL_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec3) == GL_BOOL_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec4) == GL_BOOL_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat2) == GL_FLOAT_MAT2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat3) == GL_FLOAT_MAT3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch"); + +static_assert(underlying_type(BufferUsage::StreamDraw) == GL_STREAM_DRAW, "OpenGL type mismatch"); +static_assert(underlying_type(BufferUsage::StaticDraw) == GL_STATIC_DRAW, "OpenGL type mismatch"); +static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "OpenGL type mismatch"); + static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch"); Context::Context() = default; Context::~Context() { - reset(); + if (cleanupOnDestruction) { + reset(); + } } void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) { @@ -164,25 +212,39 @@ void Context::verifyProgramLinkage(ProgramID program_) { throw std::runtime_error("program failed to link"); } -UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) { +UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size, const BufferUsage usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; vertexBuffer = result; - MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)); + MBGL_CHECK_ERROR(glBufferData(GL_ARRAY_BUFFER, size, data, static_cast<GLenum>(usage))); return result; } -UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) { +void Context::updateVertexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size) { + vertexBuffer = buffer; + MBGL_CHECK_ERROR(glBufferSubData(GL_ARRAY_BUFFER, 0, size, data)); +} + +UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size, const BufferUsage usage) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; - vertexArrayObject = 0; - elementBuffer = result; - MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)); + bindVertexArray = 0; + globalVertexArrayState.indexBuffer = result; + MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, static_cast<GLenum>(usage))); return result; } +void Context::updateIndexBuffer(UniqueBuffer& buffer, const void* data, std::size_t size) { + // Be sure to unbind any existing vertex array object before binding the index buffer + // so that we don't mess up another VAO + bindVertexArray = 0; + globalVertexArrayState.indexBuffer = buffer; + MBGL_CHECK_ERROR(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, size, data)); +} + + UniqueTexture Context::createTexture() { if (pooledTextures.empty()) { pooledTextures.resize(TextureMax); @@ -195,7 +257,14 @@ UniqueTexture Context::createTexture() { } bool Context::supportsVertexArrays() const { - return vertexArray && + static bool blacklisted = []() { + // Blacklist Adreno 3xx as it crashes on glBuffer(Sub)Data + const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + return renderer.find("Adreno (TM) 3") != std::string::npos; + }(); + + return !blacklisted && + vertexArray && vertexArray->genVertexArrays && vertexArray->bindVertexArray && vertexArray->deleteVertexArrays; @@ -203,7 +272,21 @@ bool Context::supportsVertexArrays() const { #if MBGL_HAS_BINARY_PROGRAMS bool Context::supportsProgramBinaries() const { - return programBinary && programBinary->programBinary && programBinary->getProgramBinary; + if (!programBinary || !programBinary->programBinary || !programBinary->getProgramBinary) { + return false; + } + + // Blacklist Adreno 3xx, 4xx, and 5xx GPUs due to known bugs: + // https://bugs.chromium.org/p/chromium/issues/detail?id=510637 + // https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_driver_bug_list.json#2316 + const std::string renderer = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); + if (renderer.find("Adreno (TM) 3") != std::string::npos + || renderer.find("Adreno (TM) 4") != std::string::npos + || renderer.find("Adreno (TM) 5") != std::string::npos) { + return false; + } + + return true; } optional<std::pair<BinaryProgramFormat, std::string>> @@ -229,11 +312,17 @@ optional<std::pair<BinaryProgramFormat, std::string>> Context::getBinaryProgram( } #endif -UniqueVertexArray Context::createVertexArray() { - assert(supportsVertexArrays()); - VertexArrayID id = 0; - MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); - return UniqueVertexArray(std::move(id), { this }); +VertexArray Context::createVertexArray() { + if (supportsVertexArrays()) { + VertexArrayID id = 0; + MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); + UniqueVertexArray vao(std::move(id), { this }); + return { UniqueVertexArrayState(new VertexArrayState(std::move(vao), *this), VertexArrayStateDeleter { true })}; + } else { + // On GL implementations which do not support vertex arrays, attribute bindings are global state. + // So return a VertexArray which shares our global state tracking and whose deleter is a no-op. + return { UniqueVertexArrayState(&globalVertexArrayState, VertexArrayStateDeleter { false }) }; + } } UniqueFramebuffer Context::createFramebuffer() { @@ -386,6 +475,9 @@ Framebuffer Context::createFramebuffer(const Texture& color) { Framebuffer Context::createFramebuffer(const Texture& color, const Renderbuffer<RenderbufferType::DepthComponent>& depthTarget) { + if (color.size != depthTarget.size) { + throw std::runtime_error("Renderbuffer size mismatch"); + } auto fbo = createFramebuffer(); bindFramebuffer = fbo; MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color.texture, 0)); @@ -410,7 +502,7 @@ Context::createTexture(const Size size, const void* data, TextureFormat format, void Context::updateTexture( TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) { - activeTexture = unit; + activeTextureUnit = unit; texture[unit] = id; MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width, size.height, 0, static_cast<GLenum>(format), GL_UNSIGNED_BYTE, @@ -424,7 +516,7 @@ void Context::bindTexture(Texture& obj, TextureWrap wrapX, TextureWrap wrapY) { if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) { - activeTexture = unit; + activeTextureUnit = unit; texture[unit] = obj.texture; if (filter != obj.filter || mipmap != obj.mipmap) { @@ -455,7 +547,7 @@ void Context::bindTexture(Texture& obj, } else if (texture[unit] != obj.texture) { // We are checking first to avoid setting the active texture without a subsequent // texture bind. - activeTexture = unit; + activeTextureUnit = unit; texture[unit] = obj.texture; } } @@ -487,7 +579,7 @@ void Context::setDirtyState() { clearStencil.setDirty(); program.setDirty(); lineWidth.setDirty(); - activeTexture.setDirty(); + activeTextureUnit.setDirty(); pixelStorePack.setDirty(); pixelStoreUnpack.setDirty(); #if not MBGL_USE_GLES2 @@ -501,8 +593,8 @@ void Context::setDirtyState() { tex.setDirty(); } vertexBuffer.setDirty(); - elementBuffer.setDirty(); - vertexArrayObject.setDirty(); + bindVertexArray.setDirty(); + globalVertexArrayState.setDirty(); } void Context::clear(optional<mbgl::Color> color, @@ -513,19 +605,19 @@ void Context::clear(optional<mbgl::Color> color, if (color) { mask |= GL_COLOR_BUFFER_BIT; clearColor = *color; - colorMask = { true, true, true, true }; + colorMask = value::ColorMask::Default; } if (depth) { mask |= GL_DEPTH_BUFFER_BIT; clearDepth = *depth; - depthMask = true; + depthMask = value::DepthMask::Default; } if (stencil) { mask |= GL_STENCIL_BUFFER_BIT; clearStencil = *stencil; - stencilMask = 0xFF; + stencilMask = value::StencilMask::Default; } MBGL_CHECK_ERROR(glClear(mask)); @@ -557,6 +649,13 @@ void Context::setDrawMode(const TriangleStrip&) { void Context::setDepthMode(const DepthMode& depth) { if (depth.func == DepthMode::Always && !depth.mask) { depthTest = false; + + // Workaround for rendering errors on Adreno 2xx GPUs. Depth-related state should + // not matter when the depth test is disabled, but on these GPUs it apparently does. + // https://github.com/mapbox/mapbox-gl-native/issues/9164 + depthFunc = depth.func; + depthMask = depth.mask; + depthRange = depth.range; } else { depthTest = true; depthFunc = depth.func; @@ -621,8 +720,8 @@ void Context::performCleanup() { for (const auto id : abandonedBuffers) { if (vertexBuffer == id) { vertexBuffer.setDirty(); - } else if (elementBuffer == id) { - elementBuffer.setDirty(); + } else if (globalVertexArrayState.indexBuffer == id) { + globalVertexArrayState.indexBuffer.setDirty(); } } MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data())); @@ -631,8 +730,10 @@ void Context::performCleanup() { if (!abandonedTextures.empty()) { for (const auto id : abandonedTextures) { - if (activeTexture == id) { - activeTexture.setDirty(); + for (auto& binding : texture) { + if (binding == id) { + binding.setDirty(); + } } } MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data())); @@ -642,8 +743,8 @@ void Context::performCleanup() { if (!abandonedVertexArrays.empty()) { assert(supportsVertexArrays()); for (const auto id : abandonedVertexArrays) { - if (vertexArrayObject == id) { - vertexArrayObject.setDirty(); + if (bindVertexArray == id) { + bindVertexArray.setDirty(); } } MBGL_CHECK_ERROR(vertexArray->deleteVertexArrays(int(abandonedVertexArrays.size()), |