blob: 6e7f87d257229b83ba786f6c6757820a08c46e3b [file] [log] [blame]
//
// 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, Vulkan, and WebGPU 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_