diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index e470cdbb77..931a7220d1 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -68,13 +68,12 @@ enum class TargetBufferFlags : uint8_t { COLOR1 = 0x2u, //!< Color buffer selected. COLOR2 = 0x4u, //!< Color buffer selected. COLOR3 = 0x8u, //!< Color buffer selected. - COLOR = COLOR0, //!< Color buffer selected. + COLOR = COLOR0, //!< \deprecated + COLOR_ALL = COLOR0 | COLOR1 | COLOR2 | COLOR3, DEPTH = 0x10u, //!< Depth buffer selected. STENCIL = 0x20u, //!< Stencil buffer selected. - COLOR_AND_DEPTH = COLOR | DEPTH, //!< Color and depth buffer selected. - COLOR_AND_STENCIL = COLOR | STENCIL, //!< Color and stencil buffer selected. DEPTH_AND_STENCIL = DEPTH | STENCIL, //!< depth and stencil buffer selected. - ALL = COLOR | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. + ALL = COLOR_ALL | DEPTH | STENCIL //!< Color, depth and stencil buffer selected. }; inline TargetBufferFlags getMRTColorFlag(size_t index) noexcept { diff --git a/filament/backend/src/opengl/OpenGLContext.h b/filament/backend/src/opengl/OpenGLContext.h index 5aab4ab343..4b45aea70e 100644 --- a/filament/backend/src/opengl/OpenGLContext.h +++ b/filament/backend/src/opengl/OpenGLContext.h @@ -89,10 +89,6 @@ public: inline void setScissor(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept; inline void viewport(GLint left, GLint bottom, GLsizei width, GLsizei height) noexcept; - inline void setClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) noexcept; - inline void setClearDepth(GLfloat depth) noexcept; - inline void setClearStencil(GLint stencil) noexcept; - void deleteBuffers(GLsizei n, const GLuint* buffers, GLenum target) noexcept; void deleteVextexArrays(GLsizei n, const GLuint* arrays) noexcept; @@ -247,12 +243,6 @@ private: vec4gli scissor { 0 }; vec4gli viewport { 0 }; } window; - - struct { - math::float4 color = {}; - GLfloat depth = 1.0f; - GLint stencil = 0; - } clears; } state; RenderPrimitive mDefaultVAO; @@ -358,25 +348,6 @@ void OpenGLContext::viewport(GLint left, GLint bottom, GLsizei width, GLsizei he }); } -void OpenGLContext::setClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) noexcept { - math::float4 color(r, g, b, a); - update_state(state.clears.color, color, [&]() { - glClearColor(r, g, b, a); - }); -} - -void OpenGLContext::setClearDepth(GLfloat depth) noexcept { - update_state(state.clears.depth, depth, [&]() { - glClearDepthf(depth); - }); -} - -void OpenGLContext::setClearStencil(GLint stencil) noexcept { - update_state(state.clears.stencil, stencil, [&]() { - glClearStencil(stencil); - }); -} - void OpenGLContext::bindVertexArray(RenderPrimitive const* p) noexcept { RenderPrimitive* vao = p ? const_cast(p) : &mDefaultVAO; update_state(state.vao.p, vao, [&]() { diff --git a/filament/backend/src/opengl/OpenGLDriver.cpp b/filament/backend/src/opengl/OpenGLDriver.cpp index addef87ff2..aaae56729a 100644 --- a/filament/backend/src/opengl/OpenGLDriver.cpp +++ b/filament/backend/src/opengl/OpenGLDriver.cpp @@ -193,7 +193,13 @@ const float2 OpenGLDriver::mClearTriangle[3] = {{ -1.0f, 3.0f }, { 3.0f, -1.0f }}; void OpenGLDriver::initClearProgram() noexcept { - const char clearVertexES[] = R"SHADER(#version 300 es + const char clearVertexES[] = +#if GLES30_HEADERS + R"SHADER(#version 300 es)SHADER" +#else + R"SHADER(#version 410 core)SHADER" +#endif + R"SHADER( uniform float depth; in vec4 pos; void main() { @@ -201,55 +207,60 @@ void OpenGLDriver::initClearProgram() noexcept { } )SHADER"; - const char clearFragmentES[] = R"SHADER(#version 300 es + const char clearFragmentES[] = +#if GLES30_HEADERS + R"SHADER(#version 300 es)SHADER" +#else + R"SHADER(#version 410 core)SHADER" +#endif + R"SHADER( precision mediump float; uniform vec4 color; - out vec4 fragColor; + out vec4 fragColor[4]; void main() { - fragColor = color; + fragColor[0] = color; + fragColor[1] = color; + fragColor[2] = color; + fragColor[3] = color; } )SHADER"; - if (GLES30_HEADERS) { - GLint status; - char const* const vsource = clearVertexES; - char const* const fsource = clearFragmentES; + GLint status; + char const* const vsource = clearVertexES; + char const* const fsource = clearFragmentES; - mClearVertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(mClearVertexShader, 1, &vsource, nullptr); - glCompileShader(mClearVertexShader); - glGetShaderiv(mClearVertexShader, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); + mClearVertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(mClearVertexShader, 1, &vsource, nullptr); + glCompileShader(mClearVertexShader); + glGetShaderiv(mClearVertexShader, GL_COMPILE_STATUS, &status); + assert(status == GL_TRUE); - mClearFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(mClearFragmentShader, 1, &fsource, nullptr); - glCompileShader(mClearFragmentShader); - glGetShaderiv(mClearFragmentShader, GL_COMPILE_STATUS, &status); - assert(status == GL_TRUE); + mClearFragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(mClearFragmentShader, 1, &fsource, nullptr); + glCompileShader(mClearFragmentShader); + glGetShaderiv(mClearFragmentShader, GL_COMPILE_STATUS, &status); + assert(status == GL_TRUE); - mClearProgram = glCreateProgram(); - glAttachShader(mClearProgram, mClearVertexShader); - glAttachShader(mClearProgram, mClearFragmentShader); - glLinkProgram(mClearProgram); - glGetProgramiv(mClearProgram, GL_LINK_STATUS, &status); - assert(status == GL_TRUE); + mClearProgram = glCreateProgram(); + glAttachShader(mClearProgram, mClearVertexShader); + glAttachShader(mClearProgram, mClearFragmentShader); + glLinkProgram(mClearProgram); + glGetProgramiv(mClearProgram, GL_LINK_STATUS, &status); + assert(status == GL_TRUE); - mContext.useProgram(mClearProgram); - mClearColorLocation = glGetUniformLocation(mClearProgram, "color"); - mClearDepthLocation = glGetUniformLocation(mClearProgram, "depth"); + mContext.useProgram(mClearProgram); + mClearColorLocation = glGetUniformLocation(mClearProgram, "color"); + mClearDepthLocation = glGetUniformLocation(mClearProgram, "depth"); - CHECK_GL_ERROR(utils::slog.e) - } + CHECK_GL_ERROR(utils::slog.e) } void OpenGLDriver::terminateClearProgram() noexcept { - if (GLES30_HEADERS) { - glDetachShader(mClearProgram, mClearVertexShader); - glDetachShader(mClearProgram, mClearFragmentShader); - glDeleteShader(mClearVertexShader); - glDeleteShader(mClearFragmentShader); - glDeleteProgram(mClearProgram); - } + glDetachShader(mClearProgram, mClearVertexShader); + glDetachShader(mClearProgram, mClearFragmentShader); + glDeleteShader(mClearVertexShader); + glDeleteShader(mClearFragmentShader); + glDeleteProgram(mClearProgram); } // ------------------------------------------------------------------------------------------------ @@ -983,12 +994,18 @@ void OpenGLDriver::createRenderTargetR(Handle rth, rt->gl.samples = samples; - for (size_t i = 0; i < 4; i++) { - if (any(targets & getMRTColorFlag(i))) { - rt->gl.color[i].texture = handle_cast(color[i].handle); - rt->gl.color[i].level = color[i].level; - framebufferTexture(color[i], rt, GL_COLOR_ATTACHMENT0 + i); + if (any(targets & TargetBufferFlags::COLOR_ALL)) { + GLenum bufs[4] = { GL_NONE }; + for (size_t i = 0; i < 4; i++) { + if (any(targets & getMRTColorFlag(i))) { + rt->gl.color[i].texture = handle_cast(color[i].handle); + rt->gl.color[i].level = color[i].level; + framebufferTexture(color[i], rt, GL_COLOR_ATTACHMENT0 + i); + bufs[i] = GL_COLOR_ATTACHMENT0 + i; + } } + glDrawBuffers(4, bufs); + CHECK_GL_ERROR(utils::slog.e) } // handle special cases first (where depth/stencil are packed) @@ -1616,10 +1633,10 @@ bool OpenGLDriver::canGenerateMipmaps() { } void OpenGLDriver::setTextureData(GLTexture* t, - uint32_t level, - uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, - uint32_t width, uint32_t height, uint32_t depth, - PixelBufferDescriptor&& p, FaceOffsets const* faceOffsets) { + uint32_t level, + uint32_t xoffset, uint32_t yoffset, uint32_t zoffset, + uint32_t width, uint32_t height, uint32_t depth, + PixelBufferDescriptor&& p, FaceOffsets const* faceOffsets) { DEBUG_MARKER() auto& gl = mContext; @@ -1978,35 +1995,30 @@ void OpenGLDriver::beginRenderPass(Handle rth, params.viewport.width, params.viewport.height); } - if (any(clearFlags & TargetBufferFlags::ALL)) { - const bool clearColor = any(clearFlags & TargetBufferFlags::COLOR); - const bool clearDepth = any(clearFlags & TargetBufferFlags::DEPTH); - const bool clearStencil = any(clearFlags & TargetBufferFlags::STENCIL); + if (any(clearFlags)) { if (respectScissor) { gl.enable(GL_SCISSOR_TEST); } else { gl.disable(GL_SCISSOR_TEST); } - if (respectScissor && GLES30_HEADERS && gl.bugs.clears_hurt_performance) { + if (respectScissor && gl.bugs.clears_hurt_performance) { // With OpenGL ES, we clear the viewport using geometry to improve performance on certain // OpenGL drivers. e.g. on Adreno this avoids needless loads from the GMEM. - clearWithGeometryPipe(clearColor, params.clearColor, - clearDepth, params.clearDepth, - clearStencil, params.clearStencil); + clearWithGeometryPipe(clearFlags, + params.clearColor, params.clearDepth, params.clearStencil); } else { - // With OpenGL we always clear using glClear() - clearWithRasterPipe(clearColor, params.clearColor, - clearDepth, params.clearDepth, - clearStencil, params.clearStencil); + // With OpenGL we always clear using glClearBuffer() + clearWithRasterPipe(clearFlags, + params.clearColor, params.clearDepth, params.clearStencil); } } #ifndef NDEBUG // clear the discarded (but not the cleared ones) buffers in debug builds - mContext.setClearColor(1, 0, 0, 1); mContext.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); mContext.disable(GL_SCISSOR_TEST); - glClear(getAttachmentBitfield(discardFlags & ~clearFlags)); + clearWithRasterPipe(discardFlags & ~clearFlags, + { 1, 0, 0, 1 }, 1.0, 0); #endif } @@ -2040,10 +2052,10 @@ void OpenGLDriver::endRenderPass(int) { #ifndef NDEBUG // clear the discarded buffers in debug builds - mContext.setClearColor(0, 1, 0, 1); mContext.bindFramebuffer(GL_FRAMEBUFFER, rt->gl.fbo); mContext.disable(GL_SCISSOR_TEST); - glClear(getAttachmentBitfield(discardFlags)); + clearWithRasterPipe(discardFlags, + { 0, 1, 0, 1 }, 1.0, 0); #endif mRenderPassTarget.clear(); @@ -2671,55 +2683,58 @@ void OpenGLDriver::finish(int) { } UTILS_NOINLINE -void OpenGLDriver::clearWithRasterPipe( - bool clearColor, float4 const& linearColor, - bool clearDepth, double depth, - bool clearStencil, uint32_t stencil) noexcept { +void OpenGLDriver::clearWithRasterPipe(TargetBufferFlags clearFlags, + math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept { DEBUG_MARKER() - auto& gl = mContext; - - GLbitfield bitmask = 0; - RasterState rs(mRasterState); - if (clearColor) { - bitmask |= GL_COLOR_BUFFER_BIT; - gl.setClearColor(linearColor.r, linearColor.g, linearColor.b, linearColor.a); + if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) { rs.colorWrite = true; } - if (clearDepth) { - bitmask |= GL_DEPTH_BUFFER_BIT; - gl.setClearDepth(GLfloat(depth)); + if (any(clearFlags & TargetBufferFlags::DEPTH)) { rs.depthWrite = true; } - if (clearStencil) { - bitmask |= GL_STENCIL_BUFFER_BIT; - gl.setClearStencil(GLint(stencil)); - // stencil state is not part of RasterState for now + // stencil state is not part of the RasterState currently + if (any(clearFlags & (TargetBufferFlags::COLOR_ALL | TargetBufferFlags::DEPTH))) { + setRasterState(rs); } - if (bitmask) { - setRasterState(rs); - glClear(bitmask); + if (any(clearFlags & TargetBufferFlags::COLOR0)) { + glClearBufferfv(GL_COLOR, 0, linearColor.v); + } + if (any(clearFlags & TargetBufferFlags::COLOR1)) { + glClearBufferfv(GL_COLOR, 1, linearColor.v); + } + if (any(clearFlags & TargetBufferFlags::COLOR2)) { + glClearBufferfv(GL_COLOR, 2, linearColor.v); + } + if (any(clearFlags & TargetBufferFlags::COLOR3)) { + glClearBufferfv(GL_COLOR, 3, linearColor.v); + } + + if ((clearFlags & TargetBufferFlags::DEPTH_AND_STENCIL) == TargetBufferFlags::DEPTH_AND_STENCIL) { + glClearBufferfi(GL_DEPTH_STENCIL, 0, depth, stencil); + } else { + if (any(clearFlags & TargetBufferFlags::DEPTH)) { + glClearBufferfv(GL_DEPTH, 0, &depth); + } + if (any(clearFlags & TargetBufferFlags::STENCIL)) { + glClearBufferiv(GL_STENCIL, 0, &stencil); + } } CHECK_GL_ERROR(utils::slog.e) } -void OpenGLDriver::clearWithGeometryPipe( - bool clearColor, float4 const& linearColor, - bool clearDepth, double depth, - bool clearStencil, uint32_t stencil) noexcept { +void OpenGLDriver::clearWithGeometryPipe(backend::TargetBufferFlags clearFlags, + math::float4 const& linearColor, double depth, uint32_t stencil) noexcept { DEBUG_MARKER() auto& gl = mContext; - // GLES is required to use this method; see initClearProgram. - assert(GLES30_HEADERS); - // TODO: handle stencil clear with geometry as well - if (clearStencil) { - gl.setClearStencil(GLint(stencil)); - glClear(GL_STENCIL_BUFFER_BIT); - CHECK_GL_ERROR(utils::slog.e) + if (any(clearFlags & TargetBufferFlags::STENCIL)) { + GLint s = GLint(stencil); + glClearBufferiv(GL_STENCIL, 0, &s); + // stencil state is not part of the RasterState currently } RasterState rs; @@ -2727,28 +2742,24 @@ void OpenGLDriver::clearWithGeometryPipe( rs.colorWrite = false; rs.depthWrite = false; - if (clearColor) { - rs.colorWrite = true; + if (any(clearFlags & (TargetBufferFlags::COLOR_ALL | TargetBufferFlags::DEPTH))) { gl.useProgram(mClearProgram); - glUniform4f(mClearColorLocation, - linearColor.r, linearColor.g, linearColor.b, linearColor.a); - CHECK_GL_ERROR(utils::slog.e) - } - if (clearDepth) { - rs.depthWrite = true; - gl.useProgram(mClearProgram); - glUniform1f(mClearDepthLocation, float(depth) * 2.0f - 1.0f); - CHECK_GL_ERROR(utils::slog.e) - } - - if (clearColor || clearDepth) { - // by the time we get here, useProgram() has been called + if (any(clearFlags & TargetBufferFlags::COLOR_ALL)) { + glUniform4fv(mClearColorLocation, 4, linearColor.v); + rs.colorWrite = true; + } + if (any(clearFlags & TargetBufferFlags::DEPTH)) { + glUniform1f(mClearDepthLocation, float(depth) * 2.0f - 1.0f); + rs.depthWrite = true; + } + // FIXME: handle MRTs setRasterState(rs); gl.bindVertexArray(nullptr); gl.bindBuffer(GL_ARRAY_BUFFER, 0); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, mClearTriangle); glDrawArrays(GL_TRIANGLES, 0, 3); + CHECK_GL_ERROR(utils::slog.e) } } diff --git a/filament/backend/src/opengl/OpenGLDriver.h b/filament/backend/src/opengl/OpenGLDriver.h index 79a86e85b4..ad57dc0e35 100644 --- a/filament/backend/src/opengl/OpenGLDriver.h +++ b/filament/backend/src/opengl/OpenGLDriver.h @@ -351,12 +351,10 @@ private: static const math::float2 mClearTriangle[3]; void initClearProgram() noexcept; void terminateClearProgram() noexcept; - void clearWithRasterPipe(bool clearColor, math::float4 const& linearColor, - bool clearDepth, double depth, - bool clearStencil, uint32_t stencil) noexcept; - void clearWithGeometryPipe(bool clearColor, math::float4 const& linearColor, - bool clearDepth, double depth, - bool clearStencil, uint32_t stencil) noexcept; + void clearWithRasterPipe(backend::TargetBufferFlags clearFlags, + math::float4 const& linearColor, GLfloat depth, GLint stencil) noexcept; + void clearWithGeometryPipe(backend::TargetBufferFlags clearFlags, + math::float4 const& linearColor, double depth, uint32_t stencil) noexcept; void setViewportScissor(backend::Viewport const& viewportScissor) noexcept; diff --git a/filament/src/RenderTarget.cpp b/filament/src/RenderTarget.cpp index 5cfff41d57..32a4781eb2 100644 --- a/filament/src/RenderTarget.cpp +++ b/filament/src/RenderTarget.cpp @@ -99,8 +99,8 @@ FRenderTarget::HwHandle FRenderTarget::createHandle(FEngine& engine, const Build FEngine::DriverApi& driver = engine.getDriverApi(); const Attachment& color = builder.mImpl->mAttachments[COLOR]; const Attachment& depth = builder.mImpl->mAttachments[DEPTH]; - const TargetBufferFlags flags = - depth.texture ? TargetBufferFlags::COLOR_AND_DEPTH : TargetBufferFlags::COLOR; + const TargetBufferFlags flags = depth.texture ? + (TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH) : TargetBufferFlags::COLOR0; // For now we do not support multisampled render targets in the public-facing API, but please // note that post-processing includes FXAA by default. diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index 8b4a607cb7..b304157007 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -166,7 +166,7 @@ void ShadowMap::render(DriverApi& driver, RenderPass& pass, FView& view) noexcep RenderPassParams params = {}; params.flags.clear = TargetBufferFlags::DEPTH; params.flags.discardStart = TargetBufferFlags::DEPTH; - params.flags.discardEnd = TargetBufferFlags::COLOR_AND_STENCIL; + params.flags.discardEnd = TargetBufferFlags::COLOR0 | TargetBufferFlags::STENCIL; params.clearDepth = 1.0; params.viewport = viewport; // disable scissor for clearing so the whole surface, but set the viewport to the diff --git a/filament/test/filament_framegraph_test.cpp b/filament/test/filament_framegraph_test.cpp index 1e900c5d47..3904bbabda 100644 --- a/filament/test/filament_framegraph_test.cpp +++ b/filament/test/filament_framegraph_test.cpp @@ -162,7 +162,7 @@ TEST(FrameGraphTest, SimpleRenderPass2) { renderPassExecuted = true; auto const& rt = resources.get(data.rt); EXPECT_TRUE(rt.target); - EXPECT_EQ(TargetBufferFlags::COLOR_AND_DEPTH, rt.params.flags.discardStart); + EXPECT_EQ(TargetBufferFlags::COLOR0 | TargetBufferFlags::DEPTH, rt.params.flags.discardStart); EXPECT_EQ(TargetBufferFlags::NONE, rt.params.flags.discardEnd); });