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 and Vulkan 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(bool allowFeedbackLoop) 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 bool mDepthStencilFeedbackLoop = false;
60 RenderTargetT *mDepthStencilRenderTarget = nullptr;
61 };
62
63 template <typename RenderTargetT>
64 RenderTargetCache<RenderTargetT>::RenderTargetCache() = default;
65
66 template <typename RenderTargetT>
67 RenderTargetCache<RenderTargetT>::~RenderTargetCache() = default;
68
69 template <typename RenderTargetT>
update(const gl::Context * context,const gl::FramebufferState & state,const gl::Framebuffer::DirtyBits & dirtyBits)70 angle::Result RenderTargetCache<RenderTargetT>::update(const gl::Context *context,
71 const gl::FramebufferState &state,
72 const gl::Framebuffer::DirtyBits &dirtyBits)
73 {
74 for (auto dirtyBit : dirtyBits)
75 {
76 switch (dirtyBit)
77 {
78 case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
79 case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
80 ANGLE_TRY(updateDepthStencilRenderTarget(context, state));
81 break;
82 case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
83 ANGLE_TRY(updateReadColorRenderTarget(context, state));
84 break;
85 case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
86 case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
87 case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
88 case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
89 case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
90 break;
91 default:
92 {
93 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
94 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
95 {
96 size_t colorIndex = static_cast<size_t>(
97 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
98 ANGLE_TRY(updateColorRenderTarget(context, state, colorIndex));
99 }
100 break;
101 }
102 }
103 }
104
105 return angle::Result::Continue;
106 }
107
108 template <typename RenderTargetT>
getColors()109 const gl::AttachmentArray<RenderTargetT *> &RenderTargetCache<RenderTargetT>::getColors() const
110 {
111 return mColorRenderTargets;
112 }
113
114 template <typename RenderTargetT>
getDepthStencil(bool allowFeedbackLoop)115 RenderTargetT *RenderTargetCache<RenderTargetT>::getDepthStencil(bool allowFeedbackLoop) const
116 {
117 return (allowFeedbackLoop || !mDepthStencilFeedbackLoop) ? mDepthStencilRenderTarget : nullptr;
118 }
119
120 template <typename RenderTargetT>
updateReadColorRenderTarget(const gl::Context * context,const gl::FramebufferState & state)121 angle::Result RenderTargetCache<RenderTargetT>::updateReadColorRenderTarget(
122 const gl::Context *context,
123 const gl::FramebufferState &state)
124 {
125 return updateCachedRenderTarget(context, state.getReadAttachment(), &mReadRenderTarget);
126 }
127
128 template <typename RenderTargetT>
updateColorRenderTarget(const gl::Context * context,const gl::FramebufferState & state,size_t colorIndex)129 angle::Result RenderTargetCache<RenderTargetT>::updateColorRenderTarget(
130 const gl::Context *context,
131 const gl::FramebufferState &state,
132 size_t colorIndex)
133 {
134 // If the color render target we're updating is also the read buffer, make sure we update the
135 // read render target also so it's not stale.
136 if (state.getReadBufferState() != GL_NONE && state.getReadIndex() == colorIndex)
137 {
138 ANGLE_TRY(updateReadColorRenderTarget(context, state));
139 }
140
141 return updateCachedRenderTarget(context, state.getColorAttachment(colorIndex),
142 &mColorRenderTargets[colorIndex]);
143 }
144
145 template <typename RenderTargetT>
updateDepthStencilRenderTarget(const gl::Context * context,const gl::FramebufferState & state)146 angle::Result RenderTargetCache<RenderTargetT>::updateDepthStencilRenderTarget(
147 const gl::Context *context,
148 const gl::FramebufferState &state)
149 {
150 mDepthStencilFeedbackLoop = state.hasDepthStencilFeedbackLoop();
151 return updateCachedRenderTarget(context, state.getDepthOrStencilAttachment(),
152 &mDepthStencilRenderTarget);
153 }
154
155 template <typename RenderTargetT>
updateCachedRenderTarget(const gl::Context * context,const gl::FramebufferAttachment * attachment,RenderTargetT ** cachedRenderTarget)156 angle::Result RenderTargetCache<RenderTargetT>::updateCachedRenderTarget(
157 const gl::Context *context,
158 const gl::FramebufferAttachment *attachment,
159 RenderTargetT **cachedRenderTarget)
160 {
161 RenderTargetT *newRenderTarget = nullptr;
162 if (attachment)
163 {
164 ASSERT(attachment->isAttached());
165 ANGLE_TRY(attachment->getRenderTarget(context, attachment->getRenderToTextureSamples(),
166 &newRenderTarget));
167 }
168 *cachedRenderTarget = newRenderTarget;
169 return angle::Result::Continue;
170 }
171
172 template <typename RenderTargetT>
getColorDraw(const gl::FramebufferState & state,size_t colorIndex)173 RenderTargetT *RenderTargetCache<RenderTargetT>::getColorDraw(const gl::FramebufferState &state,
174 size_t colorIndex) const
175 {
176 return mColorRenderTargets[colorIndex];
177 }
178
179 template <typename RenderTargetT>
getColorRead(const gl::FramebufferState & state)180 RenderTargetT *RenderTargetCache<RenderTargetT>::getColorRead(
181 const gl::FramebufferState &state) const
182 {
183 return mReadRenderTarget;
184 }
185
186 } // namespace rx
187
188 #endif // LIBANGLE_RENDERER_RENDER_TARGET_CACHE_H_
189