xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/RenderTargetCache.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2018 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // RenderTargetCache:
7 // The RenderTargetCache pattern is used in the D3D9, D3D11, Vulkan, and WebGPU back-ends. It is a
8 // cache of the various back-end objects (RenderTargets) associated with each Framebuffer
9 // attachment, be they Textures, Renderbuffers, or Surfaces. The cache is updated in Framebuffer's
10 // syncState method.
11 //
12 
13 #ifndef LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_
14 #define LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_
15 
16 #include "libANGLE/Framebuffer.h"
17 #include "libANGLE/FramebufferAttachment.h"
18 
19 namespace rx
20 {
21 
22 template <typename RenderTargetT>
23 class RenderTargetCache final : angle::NonCopyable
24 {
25   public:
26     RenderTargetCache();
27     ~RenderTargetCache();
28 
29     // Update all RenderTargets from the dirty bits.
30     angle::Result update(const gl::Context *context,
31                          const gl::FramebufferState &state,
32                          const gl::Framebuffer::DirtyBits &dirtyBits);
33 
34     // Update individual RenderTargets.
35     angle::Result updateReadColorRenderTarget(const gl::Context *context,
36                                               const gl::FramebufferState &state);
37     angle::Result updateColorRenderTarget(const gl::Context *context,
38                                           const gl::FramebufferState &state,
39                                           size_t colorIndex);
40     angle::Result updateDepthStencilRenderTarget(const gl::Context *context,
41                                                  const gl::FramebufferState &state);
42 
43     using RenderTargetArray = gl::AttachmentArray<RenderTargetT *>;
44 
45     const RenderTargetArray &getColors() const;
46     RenderTargetT *getDepthStencil() const;
47 
48     RenderTargetT *getColorDraw(const gl::FramebufferState &state, size_t colorIndex) const;
49     RenderTargetT *getColorRead(const gl::FramebufferState &state) const;
50 
51   private:
52     angle::Result updateCachedRenderTarget(const gl::Context *context,
53                                            const gl::FramebufferAttachment *attachment,
54                                            RenderTargetT **cachedRenderTarget);
55 
56     RenderTargetT *mReadRenderTarget                         = nullptr;
57     gl::AttachmentArray<RenderTargetT *> mColorRenderTargets = {};
58     // We only support a single Depth/Stencil RenderTarget currently.
59     RenderTargetT *mDepthStencilRenderTarget = nullptr;
60 };
61 
62 template <typename RenderTargetT>
63 RenderTargetCache<RenderTargetT>::RenderTargetCache() = default;
64 
65 template <typename RenderTargetT>
66 RenderTargetCache<RenderTargetT>::~RenderTargetCache() = default;
67 
68 template <typename RenderTargetT>
update(const gl::Context * context,const gl::FramebufferState & state,const gl::Framebuffer::DirtyBits & dirtyBits)69 angle::Result RenderTargetCache<RenderTargetT>::update(const gl::Context *context,
70                                                        const gl::FramebufferState &state,
71                                                        const gl::Framebuffer::DirtyBits &dirtyBits)
72 {
73     for (auto dirtyBit : dirtyBits)
74     {
75         switch (dirtyBit)
76         {
77             case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
78             case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
79                 ANGLE_TRY(updateDepthStencilRenderTarget(context, state));
80                 break;
81             case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
82                 ANGLE_TRY(updateReadColorRenderTarget(context, state));
83                 break;
84             case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
85             case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
86             case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
87             case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
88             case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
89                 break;
90             default:
91             {
92                 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
93                 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
94                 {
95                     size_t colorIndex = static_cast<size_t>(
96                         dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
97                     ANGLE_TRY(updateColorRenderTarget(context, state, colorIndex));
98                 }
99                 break;
100             }
101         }
102     }
103 
104     return angle::Result::Continue;
105 }
106 
107 template <typename RenderTargetT>
getColors()108 const gl::AttachmentArray<RenderTargetT *> &RenderTargetCache<RenderTargetT>::getColors() const
109 {
110     return mColorRenderTargets;
111 }
112 
113 template <typename RenderTargetT>
getDepthStencil()114 RenderTargetT *RenderTargetCache<RenderTargetT>::getDepthStencil() const
115 {
116     return mDepthStencilRenderTarget;
117 }
118 
119 template <typename RenderTargetT>
updateReadColorRenderTarget(const gl::Context * context,const gl::FramebufferState & state)120 angle::Result RenderTargetCache<RenderTargetT>::updateReadColorRenderTarget(
121     const gl::Context *context,
122     const gl::FramebufferState &state)
123 {
124     return updateCachedRenderTarget(context, state.getReadAttachment(), &mReadRenderTarget);
125 }
126 
127 template <typename RenderTargetT>
updateColorRenderTarget(const gl::Context * context,const gl::FramebufferState & state,size_t colorIndex)128 angle::Result RenderTargetCache<RenderTargetT>::updateColorRenderTarget(
129     const gl::Context *context,
130     const gl::FramebufferState &state,
131     size_t colorIndex)
132 {
133     const gl::FramebufferAttachment *colorAttachment = state.getColorAttachment(colorIndex);
134     ANGLE_TRY(updateCachedRenderTarget(context, colorAttachment, &mColorRenderTargets[colorIndex]));
135 
136     // If the color render target we're updating is also the read buffer, make sure we update the
137     // read render target also so it's not stale.
138     if (state.getReadBufferState() != GL_NONE && state.getReadIndex() == colorIndex)
139     {
140         if (colorAttachment == state.getReadAttachment())
141         {
142             mReadRenderTarget = mColorRenderTargets[colorIndex];
143         }
144         else
145         {
146             ANGLE_TRY(updateReadColorRenderTarget(context, state));
147         }
148     }
149 
150     return angle::Result::Continue;
151 }
152 
153 template <typename RenderTargetT>
updateDepthStencilRenderTarget(const gl::Context * context,const gl::FramebufferState & state)154 angle::Result RenderTargetCache<RenderTargetT>::updateDepthStencilRenderTarget(
155     const gl::Context *context,
156     const gl::FramebufferState &state)
157 {
158     return updateCachedRenderTarget(context, state.getDepthOrStencilAttachment(),
159                                     &mDepthStencilRenderTarget);
160 }
161 
162 template <typename RenderTargetT>
updateCachedRenderTarget(const gl::Context * context,const gl::FramebufferAttachment * attachment,RenderTargetT ** cachedRenderTarget)163 angle::Result RenderTargetCache<RenderTargetT>::updateCachedRenderTarget(
164     const gl::Context *context,
165     const gl::FramebufferAttachment *attachment,
166     RenderTargetT **cachedRenderTarget)
167 {
168     RenderTargetT *newRenderTarget = nullptr;
169     if (attachment)
170     {
171         ASSERT(attachment->isAttached());
172         ANGLE_TRY(attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(),
173                                               &newRenderTarget));
174     }
175     *cachedRenderTarget = newRenderTarget;
176     return angle::Result::Continue;
177 }
178 
179 template <typename RenderTargetT>
getColorDraw(const gl::FramebufferState & state,size_t colorIndex)180 RenderTargetT *RenderTargetCache<RenderTargetT>::getColorDraw(const gl::FramebufferState &state,
181                                                               size_t colorIndex) const
182 {
183     return mColorRenderTargets[colorIndex];
184 }
185 
186 template <typename RenderTargetT>
getColorRead(const gl::FramebufferState & state)187 RenderTargetT *RenderTargetCache<RenderTargetT>::getColorRead(
188     const gl::FramebufferState &state) const
189 {
190     return mReadRenderTarget;
191 }
192 
193 }  // namespace rx
194 
195 #endif  // LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_
196