// // Copyright 2017 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // ClearMultiviewGL: // A helper for clearing multiview side-by-side and layered framebuffers. // #include "libANGLE/renderer/gl/ClearMultiviewGL.h" #include "libANGLE/renderer/gl/FunctionsGL.h" #include "libANGLE/renderer/gl/StateManagerGL.h" #include "libANGLE/renderer/gl/TextureGL.h" #include "libANGLE/Framebuffer.h" namespace rx { ClearMultiviewGL::ClearMultiviewGL(const FunctionsGL *functions, StateManagerGL *stateManager) : mFunctions(functions), mStateManager(stateManager), mFramebuffer(0u) {} ClearMultiviewGL::~ClearMultiviewGL() { if (mFramebuffer != 0u) { mFunctions->deleteFramebuffers(1, &mFramebuffer); } } void ClearMultiviewGL::clearMultiviewFBO(const gl::FramebufferState &state, const gl::Rectangle &scissorBase, ClearCommandType clearCommandType, GLbitfield mask, GLenum buffer, GLint drawbuffer, const uint8_t *values, GLfloat depth, GLint stencil) { const gl::FramebufferAttachment *firstAttachment = state.getFirstNonNullAttachment(); if (firstAttachment->isMultiview()) { clearLayeredFBO(state, clearCommandType, mask, buffer, drawbuffer, values, depth, stencil); } } void ClearMultiviewGL::clearLayeredFBO(const gl::FramebufferState &state, ClearCommandType clearCommandType, GLbitfield mask, GLenum buffer, GLint drawbuffer, const uint8_t *values, GLfloat depth, GLint stencil) { initializeResources(); mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer); const gl::FramebufferAttachment *firstAttachment = state.getFirstNonNullAttachment(); ASSERT(firstAttachment->isMultiview()); const auto &drawBuffers = state.getDrawBufferStates(); mFunctions->drawBuffers(static_cast(drawBuffers.size()), drawBuffers.data()); // Attach the new attachments and clear. int numViews = firstAttachment->getNumViews(); int baseViewIndex = firstAttachment->getBaseViewIndex(); for (int i = 0; i < numViews; ++i) { attachTextures(state, baseViewIndex + i); genericClear(clearCommandType, mask, buffer, drawbuffer, values, depth, stencil); } detachTextures(state); } void ClearMultiviewGL::genericClear(ClearCommandType clearCommandType, GLbitfield mask, GLenum buffer, GLint drawbuffer, const uint8_t *values, GLfloat depth, GLint stencil) { switch (clearCommandType) { case ClearCommandType::Clear: mFunctions->clear(mask); break; case ClearCommandType::ClearBufferfv: mFunctions->clearBufferfv(buffer, drawbuffer, reinterpret_cast(values)); break; case ClearCommandType::ClearBufferuiv: mFunctions->clearBufferuiv(buffer, drawbuffer, reinterpret_cast(values)); break; case ClearCommandType::ClearBufferiv: mFunctions->clearBufferiv(buffer, drawbuffer, reinterpret_cast(values)); break; case ClearCommandType::ClearBufferfi: mFunctions->clearBufferfi(buffer, drawbuffer, depth, stencil); break; default: UNREACHABLE(); } } void ClearMultiviewGL::attachTextures(const gl::FramebufferState &state, int layer) { for (auto drawBufferId : state.getEnabledDrawBuffers()) { const gl::FramebufferAttachment *attachment = state.getColorAttachment(drawBufferId); if (attachment == nullptr) { continue; } const auto &imageIndex = attachment->getTextureImageIndex(); ASSERT(imageIndex.getType() == gl::TextureType::_2DArray); GLenum colorAttachment = static_cast(GL_COLOR_ATTACHMENT0 + static_cast(drawBufferId)); const TextureGL *textureGL = GetImplAs(attachment->getTexture()); mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, colorAttachment, textureGL->getTextureID(), imageIndex.getLevelIndex(), layer); } const gl::FramebufferAttachment *depthStencilAttachment = state.getDepthStencilAttachment(); const gl::FramebufferAttachment *depthAttachment = state.getDepthAttachment(); const gl::FramebufferAttachment *stencilAttachment = state.getStencilAttachment(); if (depthStencilAttachment != nullptr) { const auto &imageIndex = depthStencilAttachment->getTextureImageIndex(); ASSERT(imageIndex.getType() == gl::TextureType::_2DArray); const TextureGL *textureGL = GetImplAs(depthStencilAttachment->getTexture()); mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, textureGL->getTextureID(), imageIndex.getLevelIndex(), layer); } else if (depthAttachment != nullptr) { const auto &imageIndex = depthAttachment->getTextureImageIndex(); ASSERT(imageIndex.getType() == gl::TextureType::_2DArray); const TextureGL *textureGL = GetImplAs(depthAttachment->getTexture()); mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, textureGL->getTextureID(), imageIndex.getLevelIndex(), layer); } else if (stencilAttachment != nullptr) { const auto &imageIndex = stencilAttachment->getTextureImageIndex(); ASSERT(imageIndex.getType() == gl::TextureType::_2DArray); const TextureGL *textureGL = GetImplAs(stencilAttachment->getTexture()); mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, textureGL->getTextureID(), imageIndex.getLevelIndex(), layer); } } void ClearMultiviewGL::detachTextures(const gl::FramebufferState &state) { for (auto drawBufferId : state.getEnabledDrawBuffers()) { const gl::FramebufferAttachment *attachment = state.getColorAttachment(drawBufferId); if (attachment == nullptr) { continue; } GLenum colorAttachment = static_cast(GL_COLOR_ATTACHMENT0 + static_cast(drawBufferId)); mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, colorAttachment, 0, 0, 0); } const gl::FramebufferAttachment *depthStencilAttachment = state.getDepthStencilAttachment(); const gl::FramebufferAttachment *depthAttachment = state.getDepthAttachment(); const gl::FramebufferAttachment *stencilAttachment = state.getStencilAttachment(); if (depthStencilAttachment != nullptr) { mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0); } else if (depthAttachment != nullptr) { mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, 0, 0, 0); } else if (stencilAttachment != nullptr) { mFunctions->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, 0, 0, 0); } } void ClearMultiviewGL::initializeResources() { if (mFramebuffer == 0u) { mFunctions->genFramebuffers(1, &mFramebuffer); } ASSERT(mFramebuffer != 0u); } } // namespace rx