diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index 0c3951278d..7401c34e60 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -789,8 +789,8 @@ void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo, auto& gl = mContext; + GLenum target = GL_TEXTURE_2D; if (any(t->usage & TextureUsage::SAMPLEABLE)) { - GLenum target = GL_TEXTURE_2D; switch (t->target) { case SamplerType::SAMPLER_2D: case SamplerType::SAMPLER_2D_ARRAY: @@ -805,128 +805,131 @@ void OpenGLDriver::framebufferTexture(backend::TargetBufferInfo const& binfo, default: break; } + } - if (rt->gl.samples <= 1 || - (rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) { - // on GL3.2 / GLES3.1 and above multisample is handled when creating the texture. - // If multisampled textures are not supported and we end-up here, things should - // still work, albeit without MSAA. - gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); - switch (target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - case GL_TEXTURE_2D: - case GL_TEXTURE_2D_MULTISAMPLE: + if (rt->gl.samples <= 1 || + (rt->gl.samples > 1 && t->samples > 1 && gl.features.multisample_texture)) { + // on GL3.2 / GLES3.1 and above multisample is handled when creating the texture. + // If multisampled textures are not supported and we end-up here, things should + // still work, albeit without MSAA. + gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_MULTISAMPLE: + if (any(t->usage & TextureUsage::SAMPLEABLE)) { glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, t->gl.id, binfo.level); - break; - case GL_TEXTURE_2D_ARRAY: - // GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES - glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, - t->gl.id, binfo.level, binfo.layer); - break; - default: - // we shouldn't be here - break; - } - CHECK_GL_ERROR(utils::slog.e) - } else + } else { + assert(target == GL_TEXTURE_2D); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, + GL_RENDERBUFFER, t->gl.id); + } + break; + case GL_TEXTURE_2D_ARRAY: + // GL_TEXTURE_2D_MULTISAMPLE_ARRAY is not supported in GLES + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, + t->gl.id, binfo.level, binfo.layer); + break; + default: + // we shouldn't be here + break; + } + CHECK_GL_ERROR(utils::slog.e) + } else #ifdef GL_EXT_multisampled_render_to_texture - // EXT_multisampled_render_to_texture only support GL_COLOR_ATTACHMENT0 - if (!attachmentTypeNotSupportedByMSRTT && (t->depth <= 1) - && ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0) - || gl.ext.EXT_multisampled_render_to_texture2)) { - assert(rt->gl.samples > 1); - // We have a multi-sample rendertarget and we have EXT_multisampled_render_to_texture, - // so, we can directly use a 1-sample texture as attachment, multi-sample resolve, - // will happen automagically and efficiently in the driver. - // This extension only exists on OpenGL ES. - gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); + // EXT_multisampled_render_to_texture only support GL_COLOR_ATTACHMENT0 + if (!attachmentTypeNotSupportedByMSRTT && (t->depth <= 1) + && ((gl.ext.EXT_multisampled_render_to_texture && attachment == GL_COLOR_ATTACHMENT0) + || gl.ext.EXT_multisampled_render_to_texture2)) { + assert(rt->gl.samples > 1); + // We have a multi-sample rendertarget and we have EXT_multisampled_render_to_texture, + // so, we can directly use a 1-sample texture as attachment, multi-sample resolve, + // will happen automagically and efficiently in the driver. + // This extension only exists on OpenGL ES. + gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); + if (any(t->usage & TextureUsage::SAMPLEABLE)) { glext::glFramebufferTexture2DMultisampleEXT(GL_FRAMEBUFFER, attachment, target, t->gl.id, binfo.level, rt->gl.samples); - } else + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, + GL_RENDERBUFFER, t->gl.id); + } + } else #endif - { // here we emulate ext.EXT_multisampled_render_to_texture - assert(rt->gl.samples > 1); + { // here we emulate ext.EXT_multisampled_render_to_texture + assert(rt->gl.samples > 1); - // If the texture doesn't already have one, create a sidecar multi-sampled renderbuffer, - // which is where drawing will actually take place, make that our attachment. - gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); - if (t->gl.rb == 0) { - glGenRenderbuffers(1, &t->gl.rb); - renderBufferStorage(t->gl.rb, - t->gl.internalFormat, rt->width, rt->height, rt->gl.samples); - } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, t->gl.rb); + // If the texture doesn't already have one, create a sidecar multi-sampled renderbuffer, + // which is where drawing will actually take place, make that our attachment. + gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); + if (t->gl.rb == 0) { + glGenRenderbuffers(1, &t->gl.rb); + renderBufferStorage(t->gl.rb, + t->gl.internalFormat, rt->width, rt->height, rt->gl.samples); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, t->gl.rb); - // We also need a "read" sidecar fbo, used later for the resolve, which takes place in - // endRenderPass(). - if (!rt->gl.fbo_read) { - glGenFramebuffers(1, &rt->gl.fbo_read); - } - gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo_read); - switch (target) { - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - case GL_TEXTURE_2D: + // We also need a "read" sidecar fbo, used later for the resolve, which takes place in + // endRenderPass(). + if (!rt->gl.fbo_read) { + glGenFramebuffers(1, &rt->gl.fbo_read); + } + gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo_read); + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_2D: + if (any(t->usage & TextureUsage::SAMPLEABLE)) { glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, target, t->gl.id, binfo.level); - break; - case GL_TEXTURE_2D_ARRAY: - glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, - t->gl.id, binfo.level, binfo.layer); - break; - default: - // we shouldn't be here - break; - } - - CHECK_GL_ERROR(utils::slog.e) - - switch (attachment) { - case GL_COLOR_ATTACHMENT0: - rt->gl.resolve |= TargetBufferFlags::COLOR0; - break; - case GL_COLOR_ATTACHMENT1: - rt->gl.resolve |= TargetBufferFlags::COLOR1; - break; - case GL_COLOR_ATTACHMENT2: - rt->gl.resolve |= TargetBufferFlags::COLOR2; - break; - case GL_COLOR_ATTACHMENT3: - rt->gl.resolve |= TargetBufferFlags::COLOR3; - break; - case GL_DEPTH_ATTACHMENT: - rt->gl.resolve |= TargetBufferFlags::DEPTH; - break; - case GL_STENCIL_ATTACHMENT: - rt->gl.resolve |= TargetBufferFlags::STENCIL; - break; - case GL_DEPTH_STENCIL_ATTACHMENT: - rt->gl.resolve |= TargetBufferFlags::DEPTH; - rt->gl.resolve |= TargetBufferFlags::STENCIL; - break; - default: - break; - } + } else { + assert(target == GL_TEXTURE_2D); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, + GL_RENDERBUFFER, t->gl.id); + } + break; + case GL_TEXTURE_2D_ARRAY: + glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, + t->gl.id, binfo.level, binfo.layer); + break; + default: + // we shouldn't be here + break; } + CHECK_GL_ERROR(utils::slog.e) + + switch (attachment) { + case GL_COLOR_ATTACHMENT0: rt->gl.resolve |= TargetBufferFlags::COLOR0; break; + case GL_COLOR_ATTACHMENT1: rt->gl.resolve |= TargetBufferFlags::COLOR1; break; + case GL_COLOR_ATTACHMENT2: rt->gl.resolve |= TargetBufferFlags::COLOR2; break; + case GL_COLOR_ATTACHMENT3: rt->gl.resolve |= TargetBufferFlags::COLOR3; break; + case GL_DEPTH_ATTACHMENT: rt->gl.resolve |= TargetBufferFlags::DEPTH; break; + case GL_STENCIL_ATTACHMENT: rt->gl.resolve |= TargetBufferFlags::STENCIL; break; + case GL_DEPTH_STENCIL_ATTACHMENT: + rt->gl.resolve |= TargetBufferFlags::DEPTH; + rt->gl.resolve |= TargetBufferFlags::STENCIL; + break; + default: + break; + } + } + + if (any(t->usage & TextureUsage::SAMPLEABLE)) { // In a sense, drawing to a texture level is similar to calling setTextureData on it; in // both cases, we update the base/max LOD to give shaders access to levels as they become // available. updateTextureLodRange(t, binfo.level); - } else { - assert(std::max(uint8_t(1), t->samples) == std::max(uint8_t(1), rt->gl.samples)); - gl.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, t->gl.id); } CHECK_GL_ERROR(utils::slog.e) @@ -1143,7 +1146,7 @@ void OpenGLDriver::destroyVertexBuffer(Handle vbh) { auto& gl = mContext; GLVertexBuffer const* eb = handle_cast(vbh); GLsizei n = GLsizei(eb->bufferCount); - auto& buffers = eb->gl.buffers; + const auto& buffers = eb->gl.buffers; gl.deleteBuffers(n, buffers.data(), GL_ARRAY_BUFFER); destruct(vbh, eb); } @@ -1219,7 +1222,9 @@ void OpenGLDriver::destroyTexture(Handle th) { } } else { assert(t->gl.target == GL_RENDERBUFFER); - assert(t->gl.rb == 0); + if (t->gl.rb) { + glDeleteRenderbuffers(1, &t->gl.rb); + } glDeleteRenderbuffers(1, &t->gl.id); } if (t->gl.fence) {