| // | |
| // Copyright 2018 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. | |
| // | |
| // RenderTargetCache: | |
| // The RenderTargetCache pattern is used in the D3D9, D3D11 and Vulkan back-ends. It is a | |
| // cache of the various back-end objects (RenderTargets) associated with each Framebuffer | |
| // attachment, be they Textures, Renderbuffers, or Surfaces. The cache is updated in Framebuffer's | |
| // syncState method. | |
| // | |
| #ifndef LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_ | |
| #define LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_ | |
| #include "libANGLE/Framebuffer.h" | |
| #include "libANGLE/FramebufferAttachment.h" | |
| namespace rx | |
| { | |
| template <typename RenderTargetT> | |
| class RenderTargetCache final : angle::NonCopyable | |
| { | |
| public: | |
| RenderTargetCache(); | |
| ~RenderTargetCache(); | |
| // Update all RenderTargets from the dirty bits. | |
| angle::Result update(const gl::Context *context, | |
| const gl::FramebufferState &state, | |
| const gl::Framebuffer::DirtyBits &dirtyBits); | |
| // Update individual RenderTargets. | |
| angle::Result updateReadColorRenderTarget(const gl::Context *context, | |
| const gl::FramebufferState &state); | |
| angle::Result updateColorRenderTarget(const gl::Context *context, | |
| const gl::FramebufferState &state, | |
| size_t colorIndex); | |
| angle::Result updateDepthStencilRenderTarget(const gl::Context *context, | |
| const gl::FramebufferState &state); | |
| using RenderTargetArray = gl::AttachmentArray<RenderTargetT *>; | |
| const RenderTargetArray &getColors() const; | |
| RenderTargetT *getDepthStencil() const; | |
| RenderTargetT *getColorDraw(const gl::FramebufferState &state, size_t colorIndex) const; | |
| RenderTargetT *getColorRead(const gl::FramebufferState &state) const; | |
| private: | |
| angle::Result updateCachedRenderTarget(const gl::Context *context, | |
| const gl::FramebufferAttachment *attachment, | |
| RenderTargetT **cachedRenderTarget); | |
| RenderTargetT *mReadRenderTarget = nullptr; | |
| gl::AttachmentArray<RenderTargetT *> mColorRenderTargets = {}; | |
| // We only support a single Depth/Stencil RenderTarget currently. | |
| RenderTargetT *mDepthStencilRenderTarget = nullptr; | |
| }; | |
| template <typename RenderTargetT> | |
| RenderTargetCache<RenderTargetT>::RenderTargetCache() = default; | |
| template <typename RenderTargetT> | |
| RenderTargetCache<RenderTargetT>::~RenderTargetCache() = default; | |
| template <typename RenderTargetT> | |
| angle::Result RenderTargetCache<RenderTargetT>::update(const gl::Context *context, | |
| const gl::FramebufferState &state, | |
| const gl::Framebuffer::DirtyBits &dirtyBits) | |
| { | |
| for (auto dirtyBit : dirtyBits) | |
| { | |
| switch (dirtyBit) | |
| { | |
| case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT: | |
| case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT: | |
| ANGLE_TRY(updateDepthStencilRenderTarget(context, state)); | |
| break; | |
| case gl::Framebuffer::DIRTY_BIT_READ_BUFFER: | |
| ANGLE_TRY(updateReadColorRenderTarget(context, state)); | |
| break; | |
| case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS: | |
| case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH: | |
| case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT: | |
| case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES: | |
| case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS: | |
| break; | |
| default: | |
| { | |
| static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits"); | |
| if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) | |
| { | |
| size_t colorIndex = static_cast<size_t>( | |
| dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); | |
| ANGLE_TRY(updateColorRenderTarget(context, state, colorIndex)); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| return angle::Result::Continue; | |
| } | |
| template <typename RenderTargetT> | |
| const gl::AttachmentArray<RenderTargetT *> &RenderTargetCache<RenderTargetT>::getColors() const | |
| { | |
| return mColorRenderTargets; | |
| } | |
| template <typename RenderTargetT> | |
| RenderTargetT *RenderTargetCache<RenderTargetT>::getDepthStencil() const | |
| { | |
| return mDepthStencilRenderTarget; | |
| } | |
| template <typename RenderTargetT> | |
| angle::Result RenderTargetCache<RenderTargetT>::updateReadColorRenderTarget( | |
| const gl::Context *context, | |
| const gl::FramebufferState &state) | |
| { | |
| return updateCachedRenderTarget(context, state.getReadAttachment(), &mReadRenderTarget); | |
| } | |
| template <typename RenderTargetT> | |
| angle::Result RenderTargetCache<RenderTargetT>::updateColorRenderTarget( | |
| const gl::Context *context, | |
| const gl::FramebufferState &state, | |
| size_t colorIndex) | |
| { | |
| // If the color render target we're updating is also the read buffer, make sure we update the | |
| // read render target also so it's not stale. | |
| if (state.getReadBufferState() != GL_NONE && state.getReadIndex() == colorIndex) | |
| { | |
| ANGLE_TRY(updateReadColorRenderTarget(context, state)); | |
| } | |
| return updateCachedRenderTarget(context, state.getColorAttachment(colorIndex), | |
| &mColorRenderTargets[colorIndex]); | |
| } | |
| template <typename RenderTargetT> | |
| angle::Result RenderTargetCache<RenderTargetT>::updateDepthStencilRenderTarget( | |
| const gl::Context *context, | |
| const gl::FramebufferState &state) | |
| { | |
| return updateCachedRenderTarget(context, state.getDepthOrStencilAttachment(), | |
| &mDepthStencilRenderTarget); | |
| } | |
| template <typename RenderTargetT> | |
| angle::Result RenderTargetCache<RenderTargetT>::updateCachedRenderTarget( | |
| const gl::Context *context, | |
| const gl::FramebufferAttachment *attachment, | |
| RenderTargetT **cachedRenderTarget) | |
| { | |
| RenderTargetT *newRenderTarget = nullptr; | |
| if (attachment) | |
| { | |
| ASSERT(attachment->isAttached()); | |
| ANGLE_TRY(attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(), | |
| &newRenderTarget)); | |
| } | |
| *cachedRenderTarget = newRenderTarget; | |
| return angle::Result::Continue; | |
| } | |
| template <typename RenderTargetT> | |
| RenderTargetT *RenderTargetCache<RenderTargetT>::getColorDraw(const gl::FramebufferState &state, | |
| size_t colorIndex) const | |
| { | |
| return mColorRenderTargets[colorIndex]; | |
| } | |
| template <typename RenderTargetT> | |
| RenderTargetT *RenderTargetCache<RenderTargetT>::getColorRead( | |
| const gl::FramebufferState &state) const | |
| { | |
| return mReadRenderTarget; | |
| } | |
| } // namespace rx | |
| #endif // LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_ |