| // |
| // 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_ |