// // 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 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; 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 mColorRenderTargets = {}; // We only support a single Depth/Stencil RenderTarget currently. RenderTargetT *mDepthStencilRenderTarget = nullptr; }; template RenderTargetCache::RenderTargetCache() = default; template RenderTargetCache::~RenderTargetCache() = default; template angle::Result RenderTargetCache::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( dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0); ANGLE_TRY(updateColorRenderTarget(context, state, colorIndex)); } break; } } } return angle::Result::Continue; } template const gl::AttachmentArray &RenderTargetCache::getColors() const { return mColorRenderTargets; } template RenderTargetT *RenderTargetCache::getDepthStencil() const { return mDepthStencilRenderTarget; } template angle::Result RenderTargetCache::updateReadColorRenderTarget( const gl::Context *context, const gl::FramebufferState &state) { return updateCachedRenderTarget(context, state.getReadAttachment(), &mReadRenderTarget); } template angle::Result RenderTargetCache::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 angle::Result RenderTargetCache::updateDepthStencilRenderTarget( const gl::Context *context, const gl::FramebufferState &state) { return updateCachedRenderTarget(context, state.getDepthOrStencilAttachment(), &mDepthStencilRenderTarget); } template angle::Result RenderTargetCache::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 RenderTargetT *RenderTargetCache::getColorDraw(const gl::FramebufferState &state, size_t colorIndex) const { return mColorRenderTargets[colorIndex]; } template RenderTargetT *RenderTargetCache::getColorRead( const gl::FramebufferState &state) const { return mReadRenderTarget; } } // namespace rx #endif // LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_