xref: /aosp_15_r20/external/angle/src/libANGLE/PixelLocalStorage.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2022 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker 
7*8975f5c5SAndroid Build Coastguard Worker // PixelLocalStorage.cpp: Defines the renderer-agnostic container classes
8*8975f5c5SAndroid Build Coastguard Worker // gl::PixelLocalStorage and gl::PixelLocalStoragePlane for
9*8975f5c5SAndroid Build Coastguard Worker // ANGLE_shader_pixel_local_storage.
10*8975f5c5SAndroid Build Coastguard Worker 
11*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/PixelLocalStorage.h"
12*8975f5c5SAndroid Build Coastguard Worker 
13*8975f5c5SAndroid Build Coastguard Worker #include <numeric>
14*8975f5c5SAndroid Build Coastguard Worker #include "common/FixedVector.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Framebuffer.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/context_private_call_autogen.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/ContextImpl.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/TextureImpl.h"
20*8975f5c5SAndroid Build Coastguard Worker 
21*8975f5c5SAndroid Build Coastguard Worker namespace gl
22*8975f5c5SAndroid Build Coastguard Worker {
23*8975f5c5SAndroid Build Coastguard Worker // RAII utilities for working with GL state.
24*8975f5c5SAndroid Build Coastguard Worker namespace
25*8975f5c5SAndroid Build Coastguard Worker {
26*8975f5c5SAndroid Build Coastguard Worker class ScopedBindTexture2D : angle::NonCopyable
27*8975f5c5SAndroid Build Coastguard Worker {
28*8975f5c5SAndroid Build Coastguard Worker   public:
ScopedBindTexture2D(Context * context,TextureID texture)29*8975f5c5SAndroid Build Coastguard Worker     ScopedBindTexture2D(Context *context, TextureID texture)
30*8975f5c5SAndroid Build Coastguard Worker         : mContext(context),
31*8975f5c5SAndroid Build Coastguard Worker           mSavedTexBinding2D(
32*8975f5c5SAndroid Build Coastguard Worker               mContext->getState().getSamplerTextureId(mContext->getState().getActiveSampler(),
33*8975f5c5SAndroid Build Coastguard Worker                                                        TextureType::_2D))
34*8975f5c5SAndroid Build Coastguard Worker     {
35*8975f5c5SAndroid Build Coastguard Worker         mContext->bindTexture(TextureType::_2D, texture);
36*8975f5c5SAndroid Build Coastguard Worker     }
37*8975f5c5SAndroid Build Coastguard Worker 
~ScopedBindTexture2D()38*8975f5c5SAndroid Build Coastguard Worker     ~ScopedBindTexture2D() { mContext->bindTexture(TextureType::_2D, mSavedTexBinding2D); }
39*8975f5c5SAndroid Build Coastguard Worker 
40*8975f5c5SAndroid Build Coastguard Worker   private:
41*8975f5c5SAndroid Build Coastguard Worker     Context *const mContext;
42*8975f5c5SAndroid Build Coastguard Worker     TextureID mSavedTexBinding2D;
43*8975f5c5SAndroid Build Coastguard Worker };
44*8975f5c5SAndroid Build Coastguard Worker 
45*8975f5c5SAndroid Build Coastguard Worker class ScopedRestoreDrawFramebuffer : angle::NonCopyable
46*8975f5c5SAndroid Build Coastguard Worker {
47*8975f5c5SAndroid Build Coastguard Worker   public:
ScopedRestoreDrawFramebuffer(Context * context)48*8975f5c5SAndroid Build Coastguard Worker     ScopedRestoreDrawFramebuffer(Context *context)
49*8975f5c5SAndroid Build Coastguard Worker         : mContext(context), mSavedFramebuffer(mContext->getState().getDrawFramebuffer())
50*8975f5c5SAndroid Build Coastguard Worker     {
51*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mSavedFramebuffer);
52*8975f5c5SAndroid Build Coastguard Worker     }
53*8975f5c5SAndroid Build Coastguard Worker 
~ScopedRestoreDrawFramebuffer()54*8975f5c5SAndroid Build Coastguard Worker     ~ScopedRestoreDrawFramebuffer() { mContext->bindDrawFramebuffer(mSavedFramebuffer->id()); }
55*8975f5c5SAndroid Build Coastguard Worker 
56*8975f5c5SAndroid Build Coastguard Worker   private:
57*8975f5c5SAndroid Build Coastguard Worker     Context *const mContext;
58*8975f5c5SAndroid Build Coastguard Worker     Framebuffer *const mSavedFramebuffer;
59*8975f5c5SAndroid Build Coastguard Worker };
60*8975f5c5SAndroid Build Coastguard Worker 
61*8975f5c5SAndroid Build Coastguard Worker class ScopedDisableScissor : angle::NonCopyable
62*8975f5c5SAndroid Build Coastguard Worker {
63*8975f5c5SAndroid Build Coastguard Worker   public:
ScopedDisableScissor(Context * context)64*8975f5c5SAndroid Build Coastguard Worker     ScopedDisableScissor(Context *context)
65*8975f5c5SAndroid Build Coastguard Worker         : mContext(context), mScissorTestEnabled(mContext->getState().isScissorTestEnabled())
66*8975f5c5SAndroid Build Coastguard Worker     {
67*8975f5c5SAndroid Build Coastguard Worker         if (mScissorTestEnabled)
68*8975f5c5SAndroid Build Coastguard Worker         {
69*8975f5c5SAndroid Build Coastguard Worker             ContextPrivateDisable(mContext->getMutablePrivateState(),
70*8975f5c5SAndroid Build Coastguard Worker                                   mContext->getMutablePrivateStateCache(), GL_SCISSOR_TEST);
71*8975f5c5SAndroid Build Coastguard Worker         }
72*8975f5c5SAndroid Build Coastguard Worker     }
73*8975f5c5SAndroid Build Coastguard Worker 
~ScopedDisableScissor()74*8975f5c5SAndroid Build Coastguard Worker     ~ScopedDisableScissor()
75*8975f5c5SAndroid Build Coastguard Worker     {
76*8975f5c5SAndroid Build Coastguard Worker         if (mScissorTestEnabled)
77*8975f5c5SAndroid Build Coastguard Worker         {
78*8975f5c5SAndroid Build Coastguard Worker             ContextPrivateEnable(mContext->getMutablePrivateState(),
79*8975f5c5SAndroid Build Coastguard Worker                                  mContext->getMutablePrivateStateCache(), GL_SCISSOR_TEST);
80*8975f5c5SAndroid Build Coastguard Worker         }
81*8975f5c5SAndroid Build Coastguard Worker     }
82*8975f5c5SAndroid Build Coastguard Worker 
83*8975f5c5SAndroid Build Coastguard Worker   private:
84*8975f5c5SAndroid Build Coastguard Worker     Context *const mContext;
85*8975f5c5SAndroid Build Coastguard Worker     const GLint mScissorTestEnabled;
86*8975f5c5SAndroid Build Coastguard Worker };
87*8975f5c5SAndroid Build Coastguard Worker 
88*8975f5c5SAndroid Build Coastguard Worker class ScopedEnableColorMask : angle::NonCopyable
89*8975f5c5SAndroid Build Coastguard Worker {
90*8975f5c5SAndroid Build Coastguard Worker   public:
ScopedEnableColorMask(Context * context,int numDrawBuffers)91*8975f5c5SAndroid Build Coastguard Worker     ScopedEnableColorMask(Context *context, int numDrawBuffers)
92*8975f5c5SAndroid Build Coastguard Worker         : mContext(context), mNumDrawBuffers(numDrawBuffers)
93*8975f5c5SAndroid Build Coastguard Worker     {
94*8975f5c5SAndroid Build Coastguard Worker         const State &state = mContext->getState();
95*8975f5c5SAndroid Build Coastguard Worker         if (!mContext->getExtensions().drawBuffersIndexedAny())
96*8975f5c5SAndroid Build Coastguard Worker         {
97*8975f5c5SAndroid Build Coastguard Worker             std::array<bool, 4> &mask = mSavedColorMasks[0];
98*8975f5c5SAndroid Build Coastguard Worker             state.getBlendStateExt().getColorMaskIndexed(0, &mask[0], &mask[1], &mask[2], &mask[3]);
99*8975f5c5SAndroid Build Coastguard Worker             ContextPrivateColorMask(mContext->getMutablePrivateState(),
100*8975f5c5SAndroid Build Coastguard Worker                                     mContext->getMutablePrivateStateCache(), GL_TRUE, GL_TRUE,
101*8975f5c5SAndroid Build Coastguard Worker                                     GL_TRUE, GL_TRUE);
102*8975f5c5SAndroid Build Coastguard Worker         }
103*8975f5c5SAndroid Build Coastguard Worker         else
104*8975f5c5SAndroid Build Coastguard Worker         {
105*8975f5c5SAndroid Build Coastguard Worker             for (int i = 0; i < mNumDrawBuffers; ++i)
106*8975f5c5SAndroid Build Coastguard Worker             {
107*8975f5c5SAndroid Build Coastguard Worker                 std::array<bool, 4> &mask = mSavedColorMasks[i];
108*8975f5c5SAndroid Build Coastguard Worker                 state.getBlendStateExt().getColorMaskIndexed(i, &mask[0], &mask[1], &mask[2],
109*8975f5c5SAndroid Build Coastguard Worker                                                              &mask[3]);
110*8975f5c5SAndroid Build Coastguard Worker                 ContextPrivateColorMaski(mContext->getMutablePrivateState(),
111*8975f5c5SAndroid Build Coastguard Worker                                          mContext->getMutablePrivateStateCache(), i, GL_TRUE,
112*8975f5c5SAndroid Build Coastguard Worker                                          GL_TRUE, GL_TRUE, GL_TRUE);
113*8975f5c5SAndroid Build Coastguard Worker             }
114*8975f5c5SAndroid Build Coastguard Worker         }
115*8975f5c5SAndroid Build Coastguard Worker     }
116*8975f5c5SAndroid Build Coastguard Worker 
~ScopedEnableColorMask()117*8975f5c5SAndroid Build Coastguard Worker     ~ScopedEnableColorMask()
118*8975f5c5SAndroid Build Coastguard Worker     {
119*8975f5c5SAndroid Build Coastguard Worker         if (!mContext->getExtensions().drawBuffersIndexedAny())
120*8975f5c5SAndroid Build Coastguard Worker         {
121*8975f5c5SAndroid Build Coastguard Worker             const std::array<bool, 4> &mask = mSavedColorMasks[0];
122*8975f5c5SAndroid Build Coastguard Worker             ContextPrivateColorMask(mContext->getMutablePrivateState(),
123*8975f5c5SAndroid Build Coastguard Worker                                     mContext->getMutablePrivateStateCache(), mask[0], mask[1],
124*8975f5c5SAndroid Build Coastguard Worker                                     mask[2], mask[3]);
125*8975f5c5SAndroid Build Coastguard Worker         }
126*8975f5c5SAndroid Build Coastguard Worker         else
127*8975f5c5SAndroid Build Coastguard Worker         {
128*8975f5c5SAndroid Build Coastguard Worker             for (int i = 0; i < mNumDrawBuffers; ++i)
129*8975f5c5SAndroid Build Coastguard Worker             {
130*8975f5c5SAndroid Build Coastguard Worker                 const std::array<bool, 4> &mask = mSavedColorMasks[i];
131*8975f5c5SAndroid Build Coastguard Worker                 ContextPrivateColorMaski(mContext->getMutablePrivateState(),
132*8975f5c5SAndroid Build Coastguard Worker                                          mContext->getMutablePrivateStateCache(), i, mask[0],
133*8975f5c5SAndroid Build Coastguard Worker                                          mask[1], mask[2], mask[3]);
134*8975f5c5SAndroid Build Coastguard Worker             }
135*8975f5c5SAndroid Build Coastguard Worker         }
136*8975f5c5SAndroid Build Coastguard Worker     }
137*8975f5c5SAndroid Build Coastguard Worker 
138*8975f5c5SAndroid Build Coastguard Worker   private:
139*8975f5c5SAndroid Build Coastguard Worker     Context *const mContext;
140*8975f5c5SAndroid Build Coastguard Worker     const int mNumDrawBuffers;
141*8975f5c5SAndroid Build Coastguard Worker     DrawBuffersArray<std::array<bool, 4>> mSavedColorMasks;
142*8975f5c5SAndroid Build Coastguard Worker };
143*8975f5c5SAndroid Build Coastguard Worker }  // namespace
144*8975f5c5SAndroid Build Coastguard Worker 
PixelLocalStoragePlane()145*8975f5c5SAndroid Build Coastguard Worker PixelLocalStoragePlane::PixelLocalStoragePlane() : mTextureObserver(this, 0) {}
146*8975f5c5SAndroid Build Coastguard Worker 
~PixelLocalStoragePlane()147*8975f5c5SAndroid Build Coastguard Worker PixelLocalStoragePlane::~PixelLocalStoragePlane()
148*8975f5c5SAndroid Build Coastguard Worker {
149*8975f5c5SAndroid Build Coastguard Worker     // Call deinitialize or onContextObjectsLost first!
150*8975f5c5SAndroid Build Coastguard Worker     // (PixelLocalStorage::deleteContextObjects calls deinitialize.)
151*8975f5c5SAndroid Build Coastguard Worker     ASSERT(isDeinitialized());
152*8975f5c5SAndroid Build Coastguard Worker     // We can always expect to receive angle::SubjectMessage::TextureIDDeleted, even if our texture
153*8975f5c5SAndroid Build Coastguard Worker     // isn't deleted until context teardown. For this reason, we don't need to hold a ref on the
154*8975f5c5SAndroid Build Coastguard Worker     // underlying texture that is the subject of mTextureObserver.
155*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureObserver.getSubject() == nullptr);
156*8975f5c5SAndroid Build Coastguard Worker }
157*8975f5c5SAndroid Build Coastguard Worker 
onContextObjectsLost()158*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::onContextObjectsLost()
159*8975f5c5SAndroid Build Coastguard Worker {
160*8975f5c5SAndroid Build Coastguard Worker     // We normally call deleteTexture on the memoryless plane texture ID, since we own it, but in
161*8975f5c5SAndroid Build Coastguard Worker     // this case we can let it go.
162*8975f5c5SAndroid Build Coastguard Worker     mTextureID = TextureID();
163*8975f5c5SAndroid Build Coastguard Worker     deinitialize(nullptr);
164*8975f5c5SAndroid Build Coastguard Worker }
165*8975f5c5SAndroid Build Coastguard Worker 
deinitialize(Context * context)166*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::deinitialize(Context *context)
167*8975f5c5SAndroid Build Coastguard Worker {
168*8975f5c5SAndroid Build Coastguard Worker     if (mMemoryless && mTextureID.value != 0)
169*8975f5c5SAndroid Build Coastguard Worker     {
170*8975f5c5SAndroid Build Coastguard Worker         ASSERT(context);
171*8975f5c5SAndroid Build Coastguard Worker         context->deleteTexture(mTextureID);  // Will deinitialize the texture via observers.
172*8975f5c5SAndroid Build Coastguard Worker     }
173*8975f5c5SAndroid Build Coastguard Worker     else
174*8975f5c5SAndroid Build Coastguard Worker     {
175*8975f5c5SAndroid Build Coastguard Worker         mInternalformat = GL_NONE;
176*8975f5c5SAndroid Build Coastguard Worker         mMemoryless     = false;
177*8975f5c5SAndroid Build Coastguard Worker         mTextureID      = TextureID();
178*8975f5c5SAndroid Build Coastguard Worker         mTextureObserver.reset();
179*8975f5c5SAndroid Build Coastguard Worker     }
180*8975f5c5SAndroid Build Coastguard Worker     ASSERT(isDeinitialized());
181*8975f5c5SAndroid Build Coastguard Worker }
182*8975f5c5SAndroid Build Coastguard Worker 
setMemoryless(Context * context,GLenum internalformat)183*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::setMemoryless(Context *context, GLenum internalformat)
184*8975f5c5SAndroid Build Coastguard Worker {
185*8975f5c5SAndroid Build Coastguard Worker     deinitialize(context);
186*8975f5c5SAndroid Build Coastguard Worker     mInternalformat = internalformat;
187*8975f5c5SAndroid Build Coastguard Worker     mMemoryless     = true;
188*8975f5c5SAndroid Build Coastguard Worker     // The backing texture will get allocated lazily, once we know what dimensions it should be.
189*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureID.value == 0);
190*8975f5c5SAndroid Build Coastguard Worker     mTextureImageIndex = ImageIndex::MakeFromType(TextureType::_2D, 0, 0);
191*8975f5c5SAndroid Build Coastguard Worker }
192*8975f5c5SAndroid Build Coastguard Worker 
setTextureBacked(Context * context,Texture * tex,int level,int layer)193*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::setTextureBacked(Context *context, Texture *tex, int level, int layer)
194*8975f5c5SAndroid Build Coastguard Worker {
195*8975f5c5SAndroid Build Coastguard Worker     deinitialize(context);
196*8975f5c5SAndroid Build Coastguard Worker     ASSERT(tex->getImmutableFormat());
197*8975f5c5SAndroid Build Coastguard Worker     mInternalformat = tex->getState().getBaseLevelDesc().format.info->internalFormat;
198*8975f5c5SAndroid Build Coastguard Worker     mMemoryless     = false;
199*8975f5c5SAndroid Build Coastguard Worker     mTextureID      = tex->id();
200*8975f5c5SAndroid Build Coastguard Worker     mTextureObserver.bind(tex);
201*8975f5c5SAndroid Build Coastguard Worker     mTextureImageIndex = ImageIndex::MakeFromType(tex->getType(), level, layer);
202*8975f5c5SAndroid Build Coastguard Worker }
203*8975f5c5SAndroid Build Coastguard Worker 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)204*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::onSubjectStateChange(angle::SubjectIndex index,
205*8975f5c5SAndroid Build Coastguard Worker                                                   angle::SubjectMessage message)
206*8975f5c5SAndroid Build Coastguard Worker {
207*8975f5c5SAndroid Build Coastguard Worker     ASSERT(index == 0);
208*8975f5c5SAndroid Build Coastguard Worker     switch (message)
209*8975f5c5SAndroid Build Coastguard Worker     {
210*8975f5c5SAndroid Build Coastguard Worker         case angle::SubjectMessage::TextureIDDeleted:
211*8975f5c5SAndroid Build Coastguard Worker             // When a texture object is deleted, any pixel local storage plane to which it is bound
212*8975f5c5SAndroid Build Coastguard Worker             // is automatically deinitialized.
213*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mTextureID.value != 0);
214*8975f5c5SAndroid Build Coastguard Worker             mTextureID = TextureID();
215*8975f5c5SAndroid Build Coastguard Worker             deinitialize(nullptr);
216*8975f5c5SAndroid Build Coastguard Worker             break;
217*8975f5c5SAndroid Build Coastguard Worker         default:
218*8975f5c5SAndroid Build Coastguard Worker             break;
219*8975f5c5SAndroid Build Coastguard Worker     }
220*8975f5c5SAndroid Build Coastguard Worker }
221*8975f5c5SAndroid Build Coastguard Worker 
isDeinitialized() const222*8975f5c5SAndroid Build Coastguard Worker bool PixelLocalStoragePlane::isDeinitialized() const
223*8975f5c5SAndroid Build Coastguard Worker {
224*8975f5c5SAndroid Build Coastguard Worker     if (mInternalformat == GL_NONE)
225*8975f5c5SAndroid Build Coastguard Worker     {
226*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!isMemoryless());
227*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mTextureID.value == 0);
228*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mTextureObserver.getSubject() == nullptr);
229*8975f5c5SAndroid Build Coastguard Worker         return true;
230*8975f5c5SAndroid Build Coastguard Worker     }
231*8975f5c5SAndroid Build Coastguard Worker     return false;
232*8975f5c5SAndroid Build Coastguard Worker }
233*8975f5c5SAndroid Build Coastguard Worker 
getIntegeri(GLenum target) const234*8975f5c5SAndroid Build Coastguard Worker GLint PixelLocalStoragePlane::getIntegeri(GLenum target) const
235*8975f5c5SAndroid Build Coastguard Worker {
236*8975f5c5SAndroid Build Coastguard Worker     if (!isDeinitialized())
237*8975f5c5SAndroid Build Coastguard Worker     {
238*8975f5c5SAndroid Build Coastguard Worker         switch (target)
239*8975f5c5SAndroid Build Coastguard Worker         {
240*8975f5c5SAndroid Build Coastguard Worker             case GL_PIXEL_LOCAL_FORMAT_ANGLE:
241*8975f5c5SAndroid Build Coastguard Worker                 return mInternalformat;
242*8975f5c5SAndroid Build Coastguard Worker             case GL_PIXEL_LOCAL_TEXTURE_NAME_ANGLE:
243*8975f5c5SAndroid Build Coastguard Worker                 return isMemoryless() ? 0 : mTextureID.value;
244*8975f5c5SAndroid Build Coastguard Worker             case GL_PIXEL_LOCAL_TEXTURE_LEVEL_ANGLE:
245*8975f5c5SAndroid Build Coastguard Worker                 return isMemoryless() ? 0 : mTextureImageIndex.getLevelIndex();
246*8975f5c5SAndroid Build Coastguard Worker             case GL_PIXEL_LOCAL_TEXTURE_LAYER_ANGLE:
247*8975f5c5SAndroid Build Coastguard Worker                 return isMemoryless() ? 0 : mTextureImageIndex.getLayerIndex();
248*8975f5c5SAndroid Build Coastguard Worker         }
249*8975f5c5SAndroid Build Coastguard Worker     }
250*8975f5c5SAndroid Build Coastguard Worker     // Since GL_NONE == 0, PLS queries all return 0 when the plane is deinitialized.
251*8975f5c5SAndroid Build Coastguard Worker     static_assert(GL_NONE == 0, "Expecting GL_NONE to be zero.");
252*8975f5c5SAndroid Build Coastguard Worker     return 0;
253*8975f5c5SAndroid Build Coastguard Worker }
254*8975f5c5SAndroid Build Coastguard Worker 
getTextureImageExtents(const Context * context,Extents * extents) const255*8975f5c5SAndroid Build Coastguard Worker bool PixelLocalStoragePlane::getTextureImageExtents(const Context *context, Extents *extents) const
256*8975f5c5SAndroid Build Coastguard Worker {
257*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isDeinitialized());
258*8975f5c5SAndroid Build Coastguard Worker     if (isMemoryless())
259*8975f5c5SAndroid Build Coastguard Worker     {
260*8975f5c5SAndroid Build Coastguard Worker         return false;
261*8975f5c5SAndroid Build Coastguard Worker     }
262*8975f5c5SAndroid Build Coastguard Worker     Texture *tex = context->getTexture(mTextureID);
263*8975f5c5SAndroid Build Coastguard Worker     ASSERT(tex != nullptr);
264*8975f5c5SAndroid Build Coastguard Worker     *extents = tex->getExtents(mTextureImageIndex.getTarget(), mTextureImageIndex.getLevelIndex());
265*8975f5c5SAndroid Build Coastguard Worker     extents->depth = 0;
266*8975f5c5SAndroid Build Coastguard Worker     return true;
267*8975f5c5SAndroid Build Coastguard Worker }
268*8975f5c5SAndroid Build Coastguard Worker 
ensureBackingTextureIfMemoryless(Context * context,Extents plsExtents)269*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::ensureBackingTextureIfMemoryless(Context *context, Extents plsExtents)
270*8975f5c5SAndroid Build Coastguard Worker {
271*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isDeinitialized());
272*8975f5c5SAndroid Build Coastguard Worker     if (!isMemoryless())
273*8975f5c5SAndroid Build Coastguard Worker     {
274*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mTextureID.value != 0);
275*8975f5c5SAndroid Build Coastguard Worker         return;
276*8975f5c5SAndroid Build Coastguard Worker     }
277*8975f5c5SAndroid Build Coastguard Worker 
278*8975f5c5SAndroid Build Coastguard Worker     // Internal textures backing memoryless planes are always 2D and not mipmapped.
279*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureImageIndex.getType() == TextureType::_2D);
280*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureImageIndex.getLevelIndex() == 0);
281*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureImageIndex.getLayerIndex() == 0);
282*8975f5c5SAndroid Build Coastguard Worker 
283*8975f5c5SAndroid Build Coastguard Worker     Texture *tex = nullptr;
284*8975f5c5SAndroid Build Coastguard Worker     if (mTextureID.value != 0)
285*8975f5c5SAndroid Build Coastguard Worker     {
286*8975f5c5SAndroid Build Coastguard Worker         tex = context->getTexture(mTextureID);
287*8975f5c5SAndroid Build Coastguard Worker         ASSERT(tex != nullptr);
288*8975f5c5SAndroid Build Coastguard Worker     }
289*8975f5c5SAndroid Build Coastguard Worker 
290*8975f5c5SAndroid Build Coastguard Worker     // Do we need to allocate a new backing texture?
291*8975f5c5SAndroid Build Coastguard Worker     if (tex == nullptr ||
292*8975f5c5SAndroid Build Coastguard Worker         static_cast<GLsizei>(tex->getWidth(TextureTarget::_2D, 0)) != plsExtents.width ||
293*8975f5c5SAndroid Build Coastguard Worker         static_cast<GLsizei>(tex->getHeight(TextureTarget::_2D, 0)) != plsExtents.height)
294*8975f5c5SAndroid Build Coastguard Worker     {
295*8975f5c5SAndroid Build Coastguard Worker         // Call setMemoryless() to release our current data, if any.
296*8975f5c5SAndroid Build Coastguard Worker         setMemoryless(context, mInternalformat);
297*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mTextureID.value == 0);
298*8975f5c5SAndroid Build Coastguard Worker 
299*8975f5c5SAndroid Build Coastguard Worker         // Create a new texture that backs the memoryless plane.
300*8975f5c5SAndroid Build Coastguard Worker         mTextureID = context->createTexture();
301*8975f5c5SAndroid Build Coastguard Worker         {
302*8975f5c5SAndroid Build Coastguard Worker             ScopedBindTexture2D scopedBindTexture2D(context, mTextureID);
303*8975f5c5SAndroid Build Coastguard Worker             context->bindTexture(TextureType::_2D, mTextureID);
304*8975f5c5SAndroid Build Coastguard Worker             context->texStorage2D(TextureType::_2D, 1, mInternalformat, plsExtents.width,
305*8975f5c5SAndroid Build Coastguard Worker                                   plsExtents.height);
306*8975f5c5SAndroid Build Coastguard Worker         }
307*8975f5c5SAndroid Build Coastguard Worker 
308*8975f5c5SAndroid Build Coastguard Worker         tex = context->getTexture(mTextureID);
309*8975f5c5SAndroid Build Coastguard Worker         ASSERT(tex != nullptr);
310*8975f5c5SAndroid Build Coastguard Worker         ASSERT(tex->id() == mTextureID);
311*8975f5c5SAndroid Build Coastguard Worker         mTextureObserver.bind(tex);
312*8975f5c5SAndroid Build Coastguard Worker     }
313*8975f5c5SAndroid Build Coastguard Worker }
314*8975f5c5SAndroid Build Coastguard Worker 
attachToDrawFramebuffer(Context * context,GLenum colorAttachment) const315*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::attachToDrawFramebuffer(Context *context, GLenum colorAttachment) const
316*8975f5c5SAndroid Build Coastguard Worker {
317*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isDeinitialized());
318*8975f5c5SAndroid Build Coastguard Worker     // Call ensureBackingTextureIfMemoryless() first!
319*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureID.value != 0 && context->getTexture(mTextureID) != nullptr);
320*8975f5c5SAndroid Build Coastguard Worker     if (mTextureImageIndex.usesTex3D())  // GL_TEXTURE_3D or GL_TEXTURE_2D_ARRAY.
321*8975f5c5SAndroid Build Coastguard Worker     {
322*8975f5c5SAndroid Build Coastguard Worker         context->framebufferTextureLayer(GL_DRAW_FRAMEBUFFER, colorAttachment, mTextureID,
323*8975f5c5SAndroid Build Coastguard Worker                                          mTextureImageIndex.getLevelIndex(),
324*8975f5c5SAndroid Build Coastguard Worker                                          mTextureImageIndex.getLayerIndex());
325*8975f5c5SAndroid Build Coastguard Worker     }
326*8975f5c5SAndroid Build Coastguard Worker     else
327*8975f5c5SAndroid Build Coastguard Worker     {
328*8975f5c5SAndroid Build Coastguard Worker         context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, colorAttachment,
329*8975f5c5SAndroid Build Coastguard Worker                                       mTextureImageIndex.getTarget(), mTextureID,
330*8975f5c5SAndroid Build Coastguard Worker                                       mTextureImageIndex.getLevelIndex());
331*8975f5c5SAndroid Build Coastguard Worker     }
332*8975f5c5SAndroid Build Coastguard Worker }
333*8975f5c5SAndroid Build Coastguard Worker 
334*8975f5c5SAndroid Build Coastguard Worker // Clears the draw buffer at 0-based index 'drawBufferIdx' on the current framebuffer.
335*8975f5c5SAndroid Build Coastguard Worker class ClearBufferCommands : public PixelLocalStoragePlane::ClearCommands
336*8975f5c5SAndroid Build Coastguard Worker {
337*8975f5c5SAndroid Build Coastguard Worker   public:
ClearBufferCommands(Context * context)338*8975f5c5SAndroid Build Coastguard Worker     ClearBufferCommands(Context *context) : mContext(context) {}
339*8975f5c5SAndroid Build Coastguard Worker 
clearfv(int drawBufferIdx,const GLfloat value[]) const340*8975f5c5SAndroid Build Coastguard Worker     void clearfv(int drawBufferIdx, const GLfloat value[]) const override
341*8975f5c5SAndroid Build Coastguard Worker     {
342*8975f5c5SAndroid Build Coastguard Worker         mContext->clearBufferfv(GL_COLOR, drawBufferIdx, value);
343*8975f5c5SAndroid Build Coastguard Worker     }
344*8975f5c5SAndroid Build Coastguard Worker 
cleariv(int drawBufferIdx,const GLint value[]) const345*8975f5c5SAndroid Build Coastguard Worker     void cleariv(int drawBufferIdx, const GLint value[]) const override
346*8975f5c5SAndroid Build Coastguard Worker     {
347*8975f5c5SAndroid Build Coastguard Worker         mContext->clearBufferiv(GL_COLOR, drawBufferIdx, value);
348*8975f5c5SAndroid Build Coastguard Worker     }
349*8975f5c5SAndroid Build Coastguard Worker 
clearuiv(int drawBufferIdx,const GLuint value[]) const350*8975f5c5SAndroid Build Coastguard Worker     void clearuiv(int drawBufferIdx, const GLuint value[]) const override
351*8975f5c5SAndroid Build Coastguard Worker     {
352*8975f5c5SAndroid Build Coastguard Worker         mContext->clearBufferuiv(GL_COLOR, drawBufferIdx, value);
353*8975f5c5SAndroid Build Coastguard Worker     }
354*8975f5c5SAndroid Build Coastguard Worker 
355*8975f5c5SAndroid Build Coastguard Worker   private:
356*8975f5c5SAndroid Build Coastguard Worker     Context *const mContext;
357*8975f5c5SAndroid Build Coastguard Worker };
358*8975f5c5SAndroid Build Coastguard Worker 
359*8975f5c5SAndroid Build Coastguard Worker template <typename T, size_t N>
ClampArray(std::array<T,N> & arr,T lo,T hi)360*8975f5c5SAndroid Build Coastguard Worker void ClampArray(std::array<T, N> &arr, T lo, T hi)
361*8975f5c5SAndroid Build Coastguard Worker {
362*8975f5c5SAndroid Build Coastguard Worker     for (T &x : arr)
363*8975f5c5SAndroid Build Coastguard Worker     {
364*8975f5c5SAndroid Build Coastguard Worker         x = std::clamp(x, lo, hi);
365*8975f5c5SAndroid Build Coastguard Worker     }
366*8975f5c5SAndroid Build Coastguard Worker }
367*8975f5c5SAndroid Build Coastguard Worker 
issueClearCommand(ClearCommands * clearCommands,int target,GLenum loadop) const368*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::issueClearCommand(ClearCommands *clearCommands,
369*8975f5c5SAndroid Build Coastguard Worker                                                int target,
370*8975f5c5SAndroid Build Coastguard Worker                                                GLenum loadop) const
371*8975f5c5SAndroid Build Coastguard Worker {
372*8975f5c5SAndroid Build Coastguard Worker     switch (mInternalformat)
373*8975f5c5SAndroid Build Coastguard Worker     {
374*8975f5c5SAndroid Build Coastguard Worker         case GL_RGBA8:
375*8975f5c5SAndroid Build Coastguard Worker         case GL_R32F:
376*8975f5c5SAndroid Build Coastguard Worker         {
377*8975f5c5SAndroid Build Coastguard Worker             std::array<GLfloat, 4> clearValue = {0, 0, 0, 0};
378*8975f5c5SAndroid Build Coastguard Worker             if (loadop == GL_LOAD_OP_CLEAR_ANGLE)
379*8975f5c5SAndroid Build Coastguard Worker             {
380*8975f5c5SAndroid Build Coastguard Worker                 clearValue = mClearValuef;
381*8975f5c5SAndroid Build Coastguard Worker                 if (mInternalformat == GL_RGBA8)
382*8975f5c5SAndroid Build Coastguard Worker                 {
383*8975f5c5SAndroid Build Coastguard Worker                     ClampArray(clearValue, 0.f, 1.f);
384*8975f5c5SAndroid Build Coastguard Worker                 }
385*8975f5c5SAndroid Build Coastguard Worker             }
386*8975f5c5SAndroid Build Coastguard Worker             clearCommands->clearfv(target, clearValue.data());
387*8975f5c5SAndroid Build Coastguard Worker             break;
388*8975f5c5SAndroid Build Coastguard Worker         }
389*8975f5c5SAndroid Build Coastguard Worker         case GL_RGBA8I:
390*8975f5c5SAndroid Build Coastguard Worker         {
391*8975f5c5SAndroid Build Coastguard Worker             std::array<GLint, 4> clearValue = {0, 0, 0, 0};
392*8975f5c5SAndroid Build Coastguard Worker             if (loadop == GL_LOAD_OP_CLEAR_ANGLE)
393*8975f5c5SAndroid Build Coastguard Worker             {
394*8975f5c5SAndroid Build Coastguard Worker                 clearValue = mClearValuei;
395*8975f5c5SAndroid Build Coastguard Worker                 ClampArray(clearValue, -128, 127);
396*8975f5c5SAndroid Build Coastguard Worker             }
397*8975f5c5SAndroid Build Coastguard Worker             clearCommands->cleariv(target, clearValue.data());
398*8975f5c5SAndroid Build Coastguard Worker             break;
399*8975f5c5SAndroid Build Coastguard Worker         }
400*8975f5c5SAndroid Build Coastguard Worker         case GL_RGBA8UI:
401*8975f5c5SAndroid Build Coastguard Worker         case GL_R32UI:
402*8975f5c5SAndroid Build Coastguard Worker         {
403*8975f5c5SAndroid Build Coastguard Worker             std::array<GLuint, 4> clearValue = {0, 0, 0, 0};
404*8975f5c5SAndroid Build Coastguard Worker             if (loadop == GL_LOAD_OP_CLEAR_ANGLE)
405*8975f5c5SAndroid Build Coastguard Worker             {
406*8975f5c5SAndroid Build Coastguard Worker                 clearValue = mClearValueui;
407*8975f5c5SAndroid Build Coastguard Worker                 if (mInternalformat == GL_RGBA8UI)
408*8975f5c5SAndroid Build Coastguard Worker                 {
409*8975f5c5SAndroid Build Coastguard Worker                     ClampArray(clearValue, 0u, 255u);
410*8975f5c5SAndroid Build Coastguard Worker                 }
411*8975f5c5SAndroid Build Coastguard Worker             }
412*8975f5c5SAndroid Build Coastguard Worker             clearCommands->clearuiv(target, clearValue.data());
413*8975f5c5SAndroid Build Coastguard Worker             break;
414*8975f5c5SAndroid Build Coastguard Worker         }
415*8975f5c5SAndroid Build Coastguard Worker         default:
416*8975f5c5SAndroid Build Coastguard Worker             // Invalid PLS internalformats should not have made it this far.
417*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
418*8975f5c5SAndroid Build Coastguard Worker     }
419*8975f5c5SAndroid Build Coastguard Worker }
420*8975f5c5SAndroid Build Coastguard Worker 
bindToImage(Context * context,GLuint unit,bool needsR32Packing) const421*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStoragePlane::bindToImage(Context *context, GLuint unit, bool needsR32Packing) const
422*8975f5c5SAndroid Build Coastguard Worker {
423*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isDeinitialized());
424*8975f5c5SAndroid Build Coastguard Worker     // Call ensureBackingTextureIfMemoryless() first!
425*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mTextureID.value != 0 && context->getTexture(mTextureID) != nullptr);
426*8975f5c5SAndroid Build Coastguard Worker     GLenum imageBindingFormat = mInternalformat;
427*8975f5c5SAndroid Build Coastguard Worker     if (needsR32Packing)
428*8975f5c5SAndroid Build Coastguard Worker     {
429*8975f5c5SAndroid Build Coastguard Worker         // D3D and ES require us to pack all PLS formats into r32f, r32i, or r32ui images.
430*8975f5c5SAndroid Build Coastguard Worker         switch (imageBindingFormat)
431*8975f5c5SAndroid Build Coastguard Worker         {
432*8975f5c5SAndroid Build Coastguard Worker             case GL_RGBA8:
433*8975f5c5SAndroid Build Coastguard Worker             case GL_RGBA8UI:
434*8975f5c5SAndroid Build Coastguard Worker                 imageBindingFormat = GL_R32UI;
435*8975f5c5SAndroid Build Coastguard Worker                 break;
436*8975f5c5SAndroid Build Coastguard Worker             case GL_RGBA8I:
437*8975f5c5SAndroid Build Coastguard Worker                 imageBindingFormat = GL_R32I;
438*8975f5c5SAndroid Build Coastguard Worker                 break;
439*8975f5c5SAndroid Build Coastguard Worker         }
440*8975f5c5SAndroid Build Coastguard Worker     }
441*8975f5c5SAndroid Build Coastguard Worker     context->bindImageTexture(unit, mTextureID, mTextureImageIndex.getLevelIndex(), GL_FALSE,
442*8975f5c5SAndroid Build Coastguard Worker                               mTextureImageIndex.getLayerIndex(), GL_READ_WRITE,
443*8975f5c5SAndroid Build Coastguard Worker                               imageBindingFormat);
444*8975f5c5SAndroid Build Coastguard Worker }
445*8975f5c5SAndroid Build Coastguard Worker 
getBackingTexture(const Context * context) const446*8975f5c5SAndroid Build Coastguard Worker const Texture *PixelLocalStoragePlane::getBackingTexture(const Context *context) const
447*8975f5c5SAndroid Build Coastguard Worker {
448*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isDeinitialized());
449*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isMemoryless());
450*8975f5c5SAndroid Build Coastguard Worker     const Texture *tex = context->getTexture(mTextureID);
451*8975f5c5SAndroid Build Coastguard Worker     ASSERT(tex != nullptr);
452*8975f5c5SAndroid Build Coastguard Worker     return tex;
453*8975f5c5SAndroid Build Coastguard Worker }
454*8975f5c5SAndroid Build Coastguard Worker 
PixelLocalStorage(const ShPixelLocalStorageOptions & plsOptions,const Caps & caps)455*8975f5c5SAndroid Build Coastguard Worker PixelLocalStorage::PixelLocalStorage(const ShPixelLocalStorageOptions &plsOptions, const Caps &caps)
456*8975f5c5SAndroid Build Coastguard Worker     : mPLSOptions(plsOptions), mPlanes(caps.maxPixelLocalStoragePlanes)
457*8975f5c5SAndroid Build Coastguard Worker {}
458*8975f5c5SAndroid Build Coastguard Worker 
~PixelLocalStorage()459*8975f5c5SAndroid Build Coastguard Worker PixelLocalStorage::~PixelLocalStorage() {}
460*8975f5c5SAndroid Build Coastguard Worker 
461*8975f5c5SAndroid Build Coastguard Worker namespace
462*8975f5c5SAndroid Build Coastguard Worker {
AllPlanesDeinitialized(const angle::FixedVector<PixelLocalStoragePlane,IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> & planes,const Context * context)463*8975f5c5SAndroid Build Coastguard Worker bool AllPlanesDeinitialized(
464*8975f5c5SAndroid Build Coastguard Worker     const angle::FixedVector<PixelLocalStoragePlane, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES>
465*8975f5c5SAndroid Build Coastguard Worker         &planes,
466*8975f5c5SAndroid Build Coastguard Worker     const Context *context)
467*8975f5c5SAndroid Build Coastguard Worker {
468*8975f5c5SAndroid Build Coastguard Worker     for (const PixelLocalStoragePlane &plane : planes)
469*8975f5c5SAndroid Build Coastguard Worker     {
470*8975f5c5SAndroid Build Coastguard Worker         if (!plane.isDeinitialized())
471*8975f5c5SAndroid Build Coastguard Worker         {
472*8975f5c5SAndroid Build Coastguard Worker             return false;
473*8975f5c5SAndroid Build Coastguard Worker         }
474*8975f5c5SAndroid Build Coastguard Worker     }
475*8975f5c5SAndroid Build Coastguard Worker     return true;
476*8975f5c5SAndroid Build Coastguard Worker }
477*8975f5c5SAndroid Build Coastguard Worker }  // namespace
478*8975f5c5SAndroid Build Coastguard Worker 
onFramebufferDestroyed(const Context * context)479*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::onFramebufferDestroyed(const Context *context)
480*8975f5c5SAndroid Build Coastguard Worker {
481*8975f5c5SAndroid Build Coastguard Worker     if (!context->isReferenced())
482*8975f5c5SAndroid Build Coastguard Worker     {
483*8975f5c5SAndroid Build Coastguard Worker         // If the Context's refcount is zero, we know it's in a teardown state and we can just let
484*8975f5c5SAndroid Build Coastguard Worker         // go of our GL objects -- they get cleaned up as part of context teardown. Otherwise, the
485*8975f5c5SAndroid Build Coastguard Worker         // Context should have called deleteContextObjects before reaching this point.
486*8975f5c5SAndroid Build Coastguard Worker         onContextObjectsLost();
487*8975f5c5SAndroid Build Coastguard Worker         for (PixelLocalStoragePlane &plane : mPlanes)
488*8975f5c5SAndroid Build Coastguard Worker         {
489*8975f5c5SAndroid Build Coastguard Worker             plane.onContextObjectsLost();
490*8975f5c5SAndroid Build Coastguard Worker         }
491*8975f5c5SAndroid Build Coastguard Worker     }
492*8975f5c5SAndroid Build Coastguard Worker     // Call deleteContextObjects() when a Framebuffer is destroyed outside of context teardown!
493*8975f5c5SAndroid Build Coastguard Worker     ASSERT(AllPlanesDeinitialized(mPlanes, context));
494*8975f5c5SAndroid Build Coastguard Worker }
495*8975f5c5SAndroid Build Coastguard Worker 
deleteContextObjects(Context * context)496*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::deleteContextObjects(Context *context)
497*8975f5c5SAndroid Build Coastguard Worker {
498*8975f5c5SAndroid Build Coastguard Worker     onDeleteContextObjects(context);
499*8975f5c5SAndroid Build Coastguard Worker     for (PixelLocalStoragePlane &plane : mPlanes)
500*8975f5c5SAndroid Build Coastguard Worker     {
501*8975f5c5SAndroid Build Coastguard Worker         plane.deinitialize(context);
502*8975f5c5SAndroid Build Coastguard Worker     }
503*8975f5c5SAndroid Build Coastguard Worker }
504*8975f5c5SAndroid Build Coastguard Worker 
begin(Context * context,GLsizei n,const GLenum loadops[])505*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::begin(Context *context, GLsizei n, const GLenum loadops[])
506*8975f5c5SAndroid Build Coastguard Worker {
507*8975f5c5SAndroid Build Coastguard Worker     // Find the pixel local storage rendering dimensions.
508*8975f5c5SAndroid Build Coastguard Worker     Extents plsExtents;
509*8975f5c5SAndroid Build Coastguard Worker     bool hasPLSExtents = false;
510*8975f5c5SAndroid Build Coastguard Worker     for (GLsizei i = 0; i < n; ++i)
511*8975f5c5SAndroid Build Coastguard Worker     {
512*8975f5c5SAndroid Build Coastguard Worker         PixelLocalStoragePlane &plane = mPlanes[i];
513*8975f5c5SAndroid Build Coastguard Worker         if (plane.getTextureImageExtents(context, &plsExtents))
514*8975f5c5SAndroid Build Coastguard Worker         {
515*8975f5c5SAndroid Build Coastguard Worker             hasPLSExtents = true;
516*8975f5c5SAndroid Build Coastguard Worker             break;
517*8975f5c5SAndroid Build Coastguard Worker         }
518*8975f5c5SAndroid Build Coastguard Worker     }
519*8975f5c5SAndroid Build Coastguard Worker     if (!hasPLSExtents)
520*8975f5c5SAndroid Build Coastguard Worker     {
521*8975f5c5SAndroid Build Coastguard Worker         // All PLS planes are memoryless. Use the rendering area of the framebuffer instead.
522*8975f5c5SAndroid Build Coastguard Worker         plsExtents =
523*8975f5c5SAndroid Build Coastguard Worker             context->getState().getDrawFramebuffer()->getState().getAttachmentExtentsIntersection();
524*8975f5c5SAndroid Build Coastguard Worker         ASSERT(plsExtents.depth == 0);
525*8975f5c5SAndroid Build Coastguard Worker     }
526*8975f5c5SAndroid Build Coastguard Worker     for (GLsizei i = 0; i < n; ++i)
527*8975f5c5SAndroid Build Coastguard Worker     {
528*8975f5c5SAndroid Build Coastguard Worker         PixelLocalStoragePlane &plane = mPlanes[i];
529*8975f5c5SAndroid Build Coastguard Worker         if (mPLSOptions.type == ShPixelLocalStorageType::ImageLoadStore ||
530*8975f5c5SAndroid Build Coastguard Worker             mPLSOptions.type == ShPixelLocalStorageType::FramebufferFetch)
531*8975f5c5SAndroid Build Coastguard Worker         {
532*8975f5c5SAndroid Build Coastguard Worker             plane.ensureBackingTextureIfMemoryless(context, plsExtents);
533*8975f5c5SAndroid Build Coastguard Worker         }
534*8975f5c5SAndroid Build Coastguard Worker         plane.markActive(true);
535*8975f5c5SAndroid Build Coastguard Worker     }
536*8975f5c5SAndroid Build Coastguard Worker 
537*8975f5c5SAndroid Build Coastguard Worker     // Disable blend and enable the full color mask on the draw buffers reserved for PLS.
538*8975f5c5SAndroid Build Coastguard Worker     const Caps &caps           = context->getCaps();
539*8975f5c5SAndroid Build Coastguard Worker     GLint firstPLSDrawBuffer   = FirstOverriddenDrawBuffer(caps, n);
540*8975f5c5SAndroid Build Coastguard Worker     PrivateState *privateState = context->getMutablePrivateState();
541*8975f5c5SAndroid Build Coastguard Worker     if (firstPLSDrawBuffer == 0)
542*8975f5c5SAndroid Build Coastguard Worker     {
543*8975f5c5SAndroid Build Coastguard Worker         privateState->setBlend(false);
544*8975f5c5SAndroid Build Coastguard Worker         privateState->setColorMask(true, true, true, true);
545*8975f5c5SAndroid Build Coastguard Worker     }
546*8975f5c5SAndroid Build Coastguard Worker     else
547*8975f5c5SAndroid Build Coastguard Worker     {
548*8975f5c5SAndroid Build Coastguard Worker         ASSERT(context->getExtensions().drawBuffersIndexedAny());
549*8975f5c5SAndroid Build Coastguard Worker         for (GLint i = firstPLSDrawBuffer; i < caps.maxDrawBuffers; ++i)
550*8975f5c5SAndroid Build Coastguard Worker         {
551*8975f5c5SAndroid Build Coastguard Worker             privateState->setBlendIndexed(false, i);
552*8975f5c5SAndroid Build Coastguard Worker             privateState->setColorMaskIndexed(true, true, true, true, i);
553*8975f5c5SAndroid Build Coastguard Worker         }
554*8975f5c5SAndroid Build Coastguard Worker     }
555*8975f5c5SAndroid Build Coastguard Worker 
556*8975f5c5SAndroid Build Coastguard Worker     onBegin(context, n, loadops, plsExtents);
557*8975f5c5SAndroid Build Coastguard Worker }
558*8975f5c5SAndroid Build Coastguard Worker 
end(Context * context,GLsizei n,const GLenum storeops[])559*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::end(Context *context, GLsizei n, const GLenum storeops[])
560*8975f5c5SAndroid Build Coastguard Worker {
561*8975f5c5SAndroid Build Coastguard Worker     onEnd(context, n, storeops);
562*8975f5c5SAndroid Build Coastguard Worker 
563*8975f5c5SAndroid Build Coastguard Worker     for (GLsizei i = 0; i < n; ++i)
564*8975f5c5SAndroid Build Coastguard Worker     {
565*8975f5c5SAndroid Build Coastguard Worker         mPlanes[i].markActive(false);
566*8975f5c5SAndroid Build Coastguard Worker     }
567*8975f5c5SAndroid Build Coastguard Worker }
568*8975f5c5SAndroid Build Coastguard Worker 
barrier(Context * context)569*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::barrier(Context *context)
570*8975f5c5SAndroid Build Coastguard Worker {
571*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!context->getExtensions().shaderPixelLocalStorageCoherentANGLE);
572*8975f5c5SAndroid Build Coastguard Worker     onBarrier(context);
573*8975f5c5SAndroid Build Coastguard Worker }
574*8975f5c5SAndroid Build Coastguard Worker 
interrupt(Context * context)575*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::interrupt(Context *context)
576*8975f5c5SAndroid Build Coastguard Worker {
577*8975f5c5SAndroid Build Coastguard Worker     if (mInterruptCount == 0)
578*8975f5c5SAndroid Build Coastguard Worker     {
579*8975f5c5SAndroid Build Coastguard Worker         mActivePlanesAtInterrupt = context->getState().getPixelLocalStorageActivePlanes();
580*8975f5c5SAndroid Build Coastguard Worker         ASSERT(0 <= mActivePlanesAtInterrupt &&
581*8975f5c5SAndroid Build Coastguard Worker                mActivePlanesAtInterrupt <= IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES);
582*8975f5c5SAndroid Build Coastguard Worker         if (mActivePlanesAtInterrupt != 0)
583*8975f5c5SAndroid Build Coastguard Worker         {
584*8975f5c5SAndroid Build Coastguard Worker             context->endPixelLocalStorageImplicit();
585*8975f5c5SAndroid Build Coastguard Worker         }
586*8975f5c5SAndroid Build Coastguard Worker     }
587*8975f5c5SAndroid Build Coastguard Worker     ++mInterruptCount;
588*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mInterruptCount > 0);
589*8975f5c5SAndroid Build Coastguard Worker }
590*8975f5c5SAndroid Build Coastguard Worker 
restore(Context * context)591*8975f5c5SAndroid Build Coastguard Worker void PixelLocalStorage::restore(Context *context)
592*8975f5c5SAndroid Build Coastguard Worker {
593*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mInterruptCount > 0);
594*8975f5c5SAndroid Build Coastguard Worker     --mInterruptCount;
595*8975f5c5SAndroid Build Coastguard Worker     ASSERT(0 <= mActivePlanesAtInterrupt &&
596*8975f5c5SAndroid Build Coastguard Worker            mActivePlanesAtInterrupt <= IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES);
597*8975f5c5SAndroid Build Coastguard Worker     if (mInterruptCount == 0 && mActivePlanesAtInterrupt >= 1)
598*8975f5c5SAndroid Build Coastguard Worker     {
599*8975f5c5SAndroid Build Coastguard Worker         angle::FixedVector<GLenum, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> loadops(
600*8975f5c5SAndroid Build Coastguard Worker             mActivePlanesAtInterrupt);
601*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei i = 0; i < mActivePlanesAtInterrupt; ++i)
602*8975f5c5SAndroid Build Coastguard Worker         {
603*8975f5c5SAndroid Build Coastguard Worker             loadops[i] = mPlanes[i].isMemoryless() ? GL_DONT_CARE : GL_LOAD_OP_LOAD_ANGLE;
604*8975f5c5SAndroid Build Coastguard Worker         }
605*8975f5c5SAndroid Build Coastguard Worker         context->beginPixelLocalStorage(mActivePlanesAtInterrupt, loadops.data());
606*8975f5c5SAndroid Build Coastguard Worker     }
607*8975f5c5SAndroid Build Coastguard Worker }
608*8975f5c5SAndroid Build Coastguard Worker 
609*8975f5c5SAndroid Build Coastguard Worker namespace
610*8975f5c5SAndroid Build Coastguard Worker {
611*8975f5c5SAndroid Build Coastguard Worker // Implements pixel local storage with image load/store shader operations.
612*8975f5c5SAndroid Build Coastguard Worker class PixelLocalStorageImageLoadStore : public PixelLocalStorage
613*8975f5c5SAndroid Build Coastguard Worker {
614*8975f5c5SAndroid Build Coastguard Worker   public:
PixelLocalStorageImageLoadStore(const ShPixelLocalStorageOptions & plsOptions,const Caps & caps)615*8975f5c5SAndroid Build Coastguard Worker     PixelLocalStorageImageLoadStore(const ShPixelLocalStorageOptions &plsOptions, const Caps &caps)
616*8975f5c5SAndroid Build Coastguard Worker         : PixelLocalStorage(plsOptions, caps)
617*8975f5c5SAndroid Build Coastguard Worker     {
618*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mPLSOptions.type == ShPixelLocalStorageType::ImageLoadStore);
619*8975f5c5SAndroid Build Coastguard Worker     }
620*8975f5c5SAndroid Build Coastguard Worker 
621*8975f5c5SAndroid Build Coastguard Worker     // Call deleteContextObjects or onContextObjectsLost first!
~PixelLocalStorageImageLoadStore()622*8975f5c5SAndroid Build Coastguard Worker     ~PixelLocalStorageImageLoadStore() override
623*8975f5c5SAndroid Build Coastguard Worker     {
624*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mScratchFramebufferForClearing.value == 0);
625*8975f5c5SAndroid Build Coastguard Worker     }
626*8975f5c5SAndroid Build Coastguard Worker 
onContextObjectsLost()627*8975f5c5SAndroid Build Coastguard Worker     void onContextObjectsLost() override
628*8975f5c5SAndroid Build Coastguard Worker     {
629*8975f5c5SAndroid Build Coastguard Worker         mScratchFramebufferForClearing = FramebufferID();  // Let go of GL objects.
630*8975f5c5SAndroid Build Coastguard Worker     }
631*8975f5c5SAndroid Build Coastguard Worker 
onDeleteContextObjects(Context * context)632*8975f5c5SAndroid Build Coastguard Worker     void onDeleteContextObjects(Context *context) override
633*8975f5c5SAndroid Build Coastguard Worker     {
634*8975f5c5SAndroid Build Coastguard Worker         if (mScratchFramebufferForClearing.value != 0)
635*8975f5c5SAndroid Build Coastguard Worker         {
636*8975f5c5SAndroid Build Coastguard Worker             context->deleteFramebuffer(mScratchFramebufferForClearing);
637*8975f5c5SAndroid Build Coastguard Worker             mScratchFramebufferForClearing = FramebufferID();
638*8975f5c5SAndroid Build Coastguard Worker         }
639*8975f5c5SAndroid Build Coastguard Worker     }
640*8975f5c5SAndroid Build Coastguard Worker 
onBegin(Context * context,GLsizei n,const GLenum loadops[],Extents plsExtents)641*8975f5c5SAndroid Build Coastguard Worker     void onBegin(Context *context, GLsizei n, const GLenum loadops[], Extents plsExtents) override
642*8975f5c5SAndroid Build Coastguard Worker     {
643*8975f5c5SAndroid Build Coastguard Worker         // Save the image bindings so we can restore them during onEnd().
644*8975f5c5SAndroid Build Coastguard Worker         const State &state = context->getState();
645*8975f5c5SAndroid Build Coastguard Worker         ASSERT(static_cast<size_t>(n) <= state.getImageUnits().size());
646*8975f5c5SAndroid Build Coastguard Worker         mSavedImageBindings.clear();
647*8975f5c5SAndroid Build Coastguard Worker         mSavedImageBindings.reserve(n);
648*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei i = 0; i < n; ++i)
649*8975f5c5SAndroid Build Coastguard Worker         {
650*8975f5c5SAndroid Build Coastguard Worker             mSavedImageBindings.emplace_back(state.getImageUnit(i));
651*8975f5c5SAndroid Build Coastguard Worker         }
652*8975f5c5SAndroid Build Coastguard Worker 
653*8975f5c5SAndroid Build Coastguard Worker         Framebuffer *framebuffer = state.getDrawFramebuffer();
654*8975f5c5SAndroid Build Coastguard Worker         if (mPLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround)
655*8975f5c5SAndroid Build Coastguard Worker         {
656*8975f5c5SAndroid Build Coastguard Worker             // anglebug.com/42266263 -- Metal [[raster_order_group()]] does not work for read_write
657*8975f5c5SAndroid Build Coastguard Worker             // textures on AMD when the render pass doesn't have a color attachment on slot 0. To
658*8975f5c5SAndroid Build Coastguard Worker             // work around this we attach one of the PLS textures to GL_COLOR_ATTACHMENT0, if there
659*8975f5c5SAndroid Build Coastguard Worker             // isn't one already.
660*8975f5c5SAndroid Build Coastguard Worker             // It's important to keep the attachment enabled so that it's set in the corresponding
661*8975f5c5SAndroid Build Coastguard Worker             // MTLRenderPassAttachmentDescriptor. As the fragment shader does not have any output
662*8975f5c5SAndroid Build Coastguard Worker             // bound to this attachment, set the color write mask to all-disabled.
663*8975f5c5SAndroid Build Coastguard Worker             // Note that the PLS extension disallows simultaneously binding a single texture image
664*8975f5c5SAndroid Build Coastguard Worker             // to a PLS plane and attaching it to the draw framebuffer. Enabling this workaround on
665*8975f5c5SAndroid Build Coastguard Worker             // any other platform would yield incorrect results.
666*8975f5c5SAndroid Build Coastguard Worker             // This flag is set to true iff the framebuffer has an attachment 0 and it is enabled.
667*8975f5c5SAndroid Build Coastguard Worker             mHadColorAttachment0 = framebuffer->getDrawBufferMask().test(0);
668*8975f5c5SAndroid Build Coastguard Worker             if (!mHadColorAttachment0)
669*8975f5c5SAndroid Build Coastguard Worker             {
670*8975f5c5SAndroid Build Coastguard Worker                 // Indexed color masks are always available on Metal.
671*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(context->getExtensions().drawBuffersIndexedAny());
672*8975f5c5SAndroid Build Coastguard Worker                 // Remember the current draw buffer 0 color mask and set it to all-disabled.
673*8975f5c5SAndroid Build Coastguard Worker                 state.getBlendStateExt().getColorMaskIndexed(
674*8975f5c5SAndroid Build Coastguard Worker                     0, &mSavedColorMask[0], &mSavedColorMask[1], &mSavedColorMask[2],
675*8975f5c5SAndroid Build Coastguard Worker                     &mSavedColorMask[3]);
676*8975f5c5SAndroid Build Coastguard Worker                 ContextPrivateColorMaski(context->getMutablePrivateState(),
677*8975f5c5SAndroid Build Coastguard Worker                                          context->getMutablePrivateStateCache(), 0, false, false,
678*8975f5c5SAndroid Build Coastguard Worker                                          false, false);
679*8975f5c5SAndroid Build Coastguard Worker 
680*8975f5c5SAndroid Build Coastguard Worker                 // Remember the current draw buffer state so we can restore it during onEnd().
681*8975f5c5SAndroid Build Coastguard Worker                 const DrawBuffersVector<GLenum> &appDrawBuffers =
682*8975f5c5SAndroid Build Coastguard Worker                     framebuffer->getDrawBufferStates();
683*8975f5c5SAndroid Build Coastguard Worker                 mSavedDrawBuffers.resize(appDrawBuffers.size());
684*8975f5c5SAndroid Build Coastguard Worker                 std::copy(appDrawBuffers.begin(), appDrawBuffers.end(), mSavedDrawBuffers.begin());
685*8975f5c5SAndroid Build Coastguard Worker 
686*8975f5c5SAndroid Build Coastguard Worker                 // Turn on draw buffer 0.
687*8975f5c5SAndroid Build Coastguard Worker                 if (mSavedDrawBuffers[0] != GL_COLOR_ATTACHMENT0)
688*8975f5c5SAndroid Build Coastguard Worker                 {
689*8975f5c5SAndroid Build Coastguard Worker                     GLenum drawBuffer0   = mSavedDrawBuffers[0];
690*8975f5c5SAndroid Build Coastguard Worker                     mSavedDrawBuffers[0] = GL_COLOR_ATTACHMENT0;
691*8975f5c5SAndroid Build Coastguard Worker                     context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
692*8975f5c5SAndroid Build Coastguard Worker                                          mSavedDrawBuffers.data());
693*8975f5c5SAndroid Build Coastguard Worker                     mSavedDrawBuffers[0] = drawBuffer0;
694*8975f5c5SAndroid Build Coastguard Worker                 }
695*8975f5c5SAndroid Build Coastguard Worker 
696*8975f5c5SAndroid Build Coastguard Worker                 // Attach one of the PLS textures to GL_COLOR_ATTACHMENT0.
697*8975f5c5SAndroid Build Coastguard Worker                 getPlane(0).attachToDrawFramebuffer(context, GL_COLOR_ATTACHMENT0);
698*8975f5c5SAndroid Build Coastguard Worker             }
699*8975f5c5SAndroid Build Coastguard Worker         }
700*8975f5c5SAndroid Build Coastguard Worker         else
701*8975f5c5SAndroid Build Coastguard Worker         {
702*8975f5c5SAndroid Build Coastguard Worker             // Save the default framebuffer width/height so we can restore it during onEnd().
703*8975f5c5SAndroid Build Coastguard Worker             mSavedFramebufferDefaultWidth  = framebuffer->getDefaultWidth();
704*8975f5c5SAndroid Build Coastguard Worker             mSavedFramebufferDefaultHeight = framebuffer->getDefaultHeight();
705*8975f5c5SAndroid Build Coastguard Worker 
706*8975f5c5SAndroid Build Coastguard Worker             // Specify the framebuffer width/height explicitly in case we end up rendering
707*8975f5c5SAndroid Build Coastguard Worker             // exclusively to shader images.
708*8975f5c5SAndroid Build Coastguard Worker             context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
709*8975f5c5SAndroid Build Coastguard Worker                                            plsExtents.width);
710*8975f5c5SAndroid Build Coastguard Worker             context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
711*8975f5c5SAndroid Build Coastguard Worker                                            plsExtents.height);
712*8975f5c5SAndroid Build Coastguard Worker         }
713*8975f5c5SAndroid Build Coastguard Worker 
714*8975f5c5SAndroid Build Coastguard Worker         // Guard GL state and bind a scratch framebuffer in case we need to reallocate or clear any
715*8975f5c5SAndroid Build Coastguard Worker         // PLS planes.
716*8975f5c5SAndroid Build Coastguard Worker         const size_t maxDrawBuffers = context->getCaps().maxDrawBuffers;
717*8975f5c5SAndroid Build Coastguard Worker         ScopedRestoreDrawFramebuffer ScopedRestoreDrawFramebuffer(context);
718*8975f5c5SAndroid Build Coastguard Worker         if (mScratchFramebufferForClearing.value == 0)
719*8975f5c5SAndroid Build Coastguard Worker         {
720*8975f5c5SAndroid Build Coastguard Worker             context->genFramebuffers(1, &mScratchFramebufferForClearing);
721*8975f5c5SAndroid Build Coastguard Worker             context->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mScratchFramebufferForClearing);
722*8975f5c5SAndroid Build Coastguard Worker             // Turn on all draw buffers on the scratch framebuffer for clearing.
723*8975f5c5SAndroid Build Coastguard Worker             DrawBuffersVector<GLenum> drawBuffers(maxDrawBuffers);
724*8975f5c5SAndroid Build Coastguard Worker             std::iota(drawBuffers.begin(), drawBuffers.end(), GL_COLOR_ATTACHMENT0);
725*8975f5c5SAndroid Build Coastguard Worker             context->drawBuffers(static_cast<int>(drawBuffers.size()), drawBuffers.data());
726*8975f5c5SAndroid Build Coastguard Worker         }
727*8975f5c5SAndroid Build Coastguard Worker         else
728*8975f5c5SAndroid Build Coastguard Worker         {
729*8975f5c5SAndroid Build Coastguard Worker             context->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mScratchFramebufferForClearing);
730*8975f5c5SAndroid Build Coastguard Worker         }
731*8975f5c5SAndroid Build Coastguard Worker         ScopedDisableScissor scopedDisableScissor(context);
732*8975f5c5SAndroid Build Coastguard Worker 
733*8975f5c5SAndroid Build Coastguard Worker         // Bind and clear the PLS planes.
734*8975f5c5SAndroid Build Coastguard Worker         size_t maxClearedAttachments = 0;
735*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei i = 0; i < n;)
736*8975f5c5SAndroid Build Coastguard Worker         {
737*8975f5c5SAndroid Build Coastguard Worker             DrawBuffersVector<int> pendingClears;
738*8975f5c5SAndroid Build Coastguard Worker             for (; pendingClears.size() < maxDrawBuffers && i < n; ++i)
739*8975f5c5SAndroid Build Coastguard Worker             {
740*8975f5c5SAndroid Build Coastguard Worker                 GLenum loadop                       = loadops[i];
741*8975f5c5SAndroid Build Coastguard Worker                 const PixelLocalStoragePlane &plane = getPlane(i);
742*8975f5c5SAndroid Build Coastguard Worker                 plane.bindToImage(context, i, !mPLSOptions.supportsNativeRGBA8ImageFormats);
743*8975f5c5SAndroid Build Coastguard Worker                 if (loadop == GL_LOAD_OP_ZERO_ANGLE || loadop == GL_LOAD_OP_CLEAR_ANGLE)
744*8975f5c5SAndroid Build Coastguard Worker                 {
745*8975f5c5SAndroid Build Coastguard Worker                     plane.attachToDrawFramebuffer(
746*8975f5c5SAndroid Build Coastguard Worker                         context, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(pendingClears.size()));
747*8975f5c5SAndroid Build Coastguard Worker                     pendingClears.push_back(i);  // Defer the clear for later.
748*8975f5c5SAndroid Build Coastguard Worker                 }
749*8975f5c5SAndroid Build Coastguard Worker             }
750*8975f5c5SAndroid Build Coastguard Worker             // Clear in batches in order to be more efficient with GL state.
751*8975f5c5SAndroid Build Coastguard Worker             ScopedEnableColorMask scopedEnableColorMask(context,
752*8975f5c5SAndroid Build Coastguard Worker                                                         static_cast<int>(pendingClears.size()));
753*8975f5c5SAndroid Build Coastguard Worker             ClearBufferCommands clearBufferCommands(context);
754*8975f5c5SAndroid Build Coastguard Worker             for (size_t drawBufferIdx = 0; drawBufferIdx < pendingClears.size(); ++drawBufferIdx)
755*8975f5c5SAndroid Build Coastguard Worker             {
756*8975f5c5SAndroid Build Coastguard Worker                 int plsIdx = pendingClears[drawBufferIdx];
757*8975f5c5SAndroid Build Coastguard Worker                 getPlane(plsIdx).issueClearCommand(
758*8975f5c5SAndroid Build Coastguard Worker                     &clearBufferCommands, static_cast<int>(drawBufferIdx), loadops[plsIdx]);
759*8975f5c5SAndroid Build Coastguard Worker             }
760*8975f5c5SAndroid Build Coastguard Worker             maxClearedAttachments = std::max(maxClearedAttachments, pendingClears.size());
761*8975f5c5SAndroid Build Coastguard Worker         }
762*8975f5c5SAndroid Build Coastguard Worker 
763*8975f5c5SAndroid Build Coastguard Worker         // Detach the cleared PLS textures from the scratch framebuffer.
764*8975f5c5SAndroid Build Coastguard Worker         for (size_t i = 0; i < maxClearedAttachments; ++i)
765*8975f5c5SAndroid Build Coastguard Worker         {
766*8975f5c5SAndroid Build Coastguard Worker             context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER,
767*8975f5c5SAndroid Build Coastguard Worker                                           GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(i),
768*8975f5c5SAndroid Build Coastguard Worker                                           TextureTarget::_2D, TextureID(), 0);
769*8975f5c5SAndroid Build Coastguard Worker         }
770*8975f5c5SAndroid Build Coastguard Worker 
771*8975f5c5SAndroid Build Coastguard Worker         // Unlike other barriers, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT also synchronizes all types of
772*8975f5c5SAndroid Build Coastguard Worker         // memory accesses that happened before the barrier:
773*8975f5c5SAndroid Build Coastguard Worker         //
774*8975f5c5SAndroid Build Coastguard Worker         //   SHADER_IMAGE_ACCESS_BARRIER_BIT: Memory accesses using shader built-in image load and
775*8975f5c5SAndroid Build Coastguard Worker         //   store functions issued after the barrier will reflect data written by shaders prior to
776*8975f5c5SAndroid Build Coastguard Worker         //   the barrier. Additionally, image stores issued after the barrier will not execute until
777*8975f5c5SAndroid Build Coastguard Worker         //   all memory accesses (e.g., loads, stores, texture fetches, vertex fetches) initiated
778*8975f5c5SAndroid Build Coastguard Worker         //   prior to the barrier complete.
779*8975f5c5SAndroid Build Coastguard Worker         //
780*8975f5c5SAndroid Build Coastguard Worker         // So we don't any barriers other than GL_SHADER_IMAGE_ACCESS_BARRIER_BIT during begin().
781*8975f5c5SAndroid Build Coastguard Worker         context->memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
782*8975f5c5SAndroid Build Coastguard Worker     }
783*8975f5c5SAndroid Build Coastguard Worker 
onEnd(Context * context,GLsizei n,const GLenum storeops[])784*8975f5c5SAndroid Build Coastguard Worker     void onEnd(Context *context, GLsizei n, const GLenum storeops[]) override
785*8975f5c5SAndroid Build Coastguard Worker     {
786*8975f5c5SAndroid Build Coastguard Worker         // Restore the image bindings. Since glBindImageTexture and any commands that modify
787*8975f5c5SAndroid Build Coastguard Worker         // textures are banned while PLS is active, these will all still be alive and valid.
788*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mSavedImageBindings.size() == static_cast<size_t>(n));
789*8975f5c5SAndroid Build Coastguard Worker         for (GLuint unit = 0; unit < mSavedImageBindings.size(); ++unit)
790*8975f5c5SAndroid Build Coastguard Worker         {
791*8975f5c5SAndroid Build Coastguard Worker             ImageUnit &binding = mSavedImageBindings[unit];
792*8975f5c5SAndroid Build Coastguard Worker             context->bindImageTexture(unit, binding.texture.id(), binding.level, binding.layered,
793*8975f5c5SAndroid Build Coastguard Worker                                       binding.layer, binding.access, binding.format);
794*8975f5c5SAndroid Build Coastguard Worker 
795*8975f5c5SAndroid Build Coastguard Worker             // BindingPointers have to be explicitly cleaned up.
796*8975f5c5SAndroid Build Coastguard Worker             binding.texture.set(context, nullptr);
797*8975f5c5SAndroid Build Coastguard Worker         }
798*8975f5c5SAndroid Build Coastguard Worker         mSavedImageBindings.clear();
799*8975f5c5SAndroid Build Coastguard Worker 
800*8975f5c5SAndroid Build Coastguard Worker         if (mPLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround)
801*8975f5c5SAndroid Build Coastguard Worker         {
802*8975f5c5SAndroid Build Coastguard Worker             if (!mHadColorAttachment0)
803*8975f5c5SAndroid Build Coastguard Worker             {
804*8975f5c5SAndroid Build Coastguard Worker                 // Detach the PLS texture we attached to GL_COLOR_ATTACHMENT0.
805*8975f5c5SAndroid Build Coastguard Worker                 context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
806*8975f5c5SAndroid Build Coastguard Worker                                               TextureTarget::_2D, TextureID(), 0);
807*8975f5c5SAndroid Build Coastguard Worker 
808*8975f5c5SAndroid Build Coastguard Worker                 // Restore the draw buffer state from before PLS was enabled.
809*8975f5c5SAndroid Build Coastguard Worker                 if (mSavedDrawBuffers[0] != GL_COLOR_ATTACHMENT0)
810*8975f5c5SAndroid Build Coastguard Worker                 {
811*8975f5c5SAndroid Build Coastguard Worker                     context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
812*8975f5c5SAndroid Build Coastguard Worker                                          mSavedDrawBuffers.data());
813*8975f5c5SAndroid Build Coastguard Worker                 }
814*8975f5c5SAndroid Build Coastguard Worker                 mSavedDrawBuffers.clear();
815*8975f5c5SAndroid Build Coastguard Worker 
816*8975f5c5SAndroid Build Coastguard Worker                 // Restore the draw buffer 0 color mask.
817*8975f5c5SAndroid Build Coastguard Worker                 ContextPrivateColorMaski(
818*8975f5c5SAndroid Build Coastguard Worker                     context->getMutablePrivateState(), context->getMutablePrivateStateCache(), 0,
819*8975f5c5SAndroid Build Coastguard Worker                     mSavedColorMask[0], mSavedColorMask[1], mSavedColorMask[2], mSavedColorMask[3]);
820*8975f5c5SAndroid Build Coastguard Worker             }
821*8975f5c5SAndroid Build Coastguard Worker         }
822*8975f5c5SAndroid Build Coastguard Worker         else
823*8975f5c5SAndroid Build Coastguard Worker         {
824*8975f5c5SAndroid Build Coastguard Worker             // Restore the default framebuffer width/height.
825*8975f5c5SAndroid Build Coastguard Worker             context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
826*8975f5c5SAndroid Build Coastguard Worker                                            mSavedFramebufferDefaultWidth);
827*8975f5c5SAndroid Build Coastguard Worker             context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
828*8975f5c5SAndroid Build Coastguard Worker                                            mSavedFramebufferDefaultHeight);
829*8975f5c5SAndroid Build Coastguard Worker         }
830*8975f5c5SAndroid Build Coastguard Worker 
831*8975f5c5SAndroid Build Coastguard Worker         // We need ALL_BARRIER_BITS during end() because GL_SHADER_IMAGE_ACCESS_BARRIER_BIT doesn't
832*8975f5c5SAndroid Build Coastguard Worker         // synchronize all types of memory accesses that can happen after the barrier.
833*8975f5c5SAndroid Build Coastguard Worker         context->memoryBarrier(GL_ALL_BARRIER_BITS);
834*8975f5c5SAndroid Build Coastguard Worker     }
835*8975f5c5SAndroid Build Coastguard Worker 
onBarrier(Context * context)836*8975f5c5SAndroid Build Coastguard Worker     void onBarrier(Context *context) override
837*8975f5c5SAndroid Build Coastguard Worker     {
838*8975f5c5SAndroid Build Coastguard Worker         context->memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
839*8975f5c5SAndroid Build Coastguard Worker     }
840*8975f5c5SAndroid Build Coastguard Worker 
841*8975f5c5SAndroid Build Coastguard Worker   private:
842*8975f5c5SAndroid Build Coastguard Worker     // D3D and ES require us to pack all PLS formats into r32f, r32i, or r32ui images.
843*8975f5c5SAndroid Build Coastguard Worker     FramebufferID mScratchFramebufferForClearing{};
844*8975f5c5SAndroid Build Coastguard Worker 
845*8975f5c5SAndroid Build Coastguard Worker     // Saved values to restore during onEnd().
846*8975f5c5SAndroid Build Coastguard Worker     std::vector<ImageUnit> mSavedImageBindings;
847*8975f5c5SAndroid Build Coastguard Worker     // If mPLSOptions.plsRenderPassNeedsColorAttachmentWorkaround.
848*8975f5c5SAndroid Build Coastguard Worker     bool mHadColorAttachment0;
849*8975f5c5SAndroid Build Coastguard Worker     std::array<bool, 4> mSavedColorMask;
850*8975f5c5SAndroid Build Coastguard Worker     DrawBuffersVector<GLenum> mSavedDrawBuffers;
851*8975f5c5SAndroid Build Coastguard Worker     // If !mPLSOptions.plsRenderPassNeedsColorAttachmentWorkaround.
852*8975f5c5SAndroid Build Coastguard Worker     GLint mSavedFramebufferDefaultWidth;
853*8975f5c5SAndroid Build Coastguard Worker     GLint mSavedFramebufferDefaultHeight;
854*8975f5c5SAndroid Build Coastguard Worker };
855*8975f5c5SAndroid Build Coastguard Worker 
856*8975f5c5SAndroid Build Coastguard Worker // Implements pixel local storage via framebuffer fetch.
857*8975f5c5SAndroid Build Coastguard Worker class PixelLocalStorageFramebufferFetch : public PixelLocalStorage
858*8975f5c5SAndroid Build Coastguard Worker {
859*8975f5c5SAndroid Build Coastguard Worker   public:
PixelLocalStorageFramebufferFetch(const ShPixelLocalStorageOptions & plsOptions,const Caps & caps)860*8975f5c5SAndroid Build Coastguard Worker     PixelLocalStorageFramebufferFetch(const ShPixelLocalStorageOptions &plsOptions,
861*8975f5c5SAndroid Build Coastguard Worker                                       const Caps &caps)
862*8975f5c5SAndroid Build Coastguard Worker         : PixelLocalStorage(plsOptions, caps)
863*8975f5c5SAndroid Build Coastguard Worker     {
864*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mPLSOptions.type == ShPixelLocalStorageType::FramebufferFetch);
865*8975f5c5SAndroid Build Coastguard Worker     }
866*8975f5c5SAndroid Build Coastguard Worker 
onContextObjectsLost()867*8975f5c5SAndroid Build Coastguard Worker     void onContextObjectsLost() override {}
868*8975f5c5SAndroid Build Coastguard Worker 
onDeleteContextObjects(Context *)869*8975f5c5SAndroid Build Coastguard Worker     void onDeleteContextObjects(Context *) override {}
870*8975f5c5SAndroid Build Coastguard Worker 
onBegin(Context * context,GLsizei n,const GLenum loadops[],Extents plsExtents)871*8975f5c5SAndroid Build Coastguard Worker     void onBegin(Context *context, GLsizei n, const GLenum loadops[], Extents plsExtents) override
872*8975f5c5SAndroid Build Coastguard Worker     {
873*8975f5c5SAndroid Build Coastguard Worker         const Caps &caps                                = context->getCaps();
874*8975f5c5SAndroid Build Coastguard Worker         Framebuffer *framebuffer                        = context->getState().getDrawFramebuffer();
875*8975f5c5SAndroid Build Coastguard Worker         const DrawBuffersVector<GLenum> &appDrawBuffers = framebuffer->getDrawBufferStates();
876*8975f5c5SAndroid Build Coastguard Worker 
877*8975f5c5SAndroid Build Coastguard Worker         // Remember the current draw buffer state so we can restore it during onEnd().
878*8975f5c5SAndroid Build Coastguard Worker         mSavedDrawBuffers.resize(appDrawBuffers.size());
879*8975f5c5SAndroid Build Coastguard Worker         std::copy(appDrawBuffers.begin(), appDrawBuffers.end(), mSavedDrawBuffers.begin());
880*8975f5c5SAndroid Build Coastguard Worker 
881*8975f5c5SAndroid Build Coastguard Worker         // Set up new draw buffers for PLS.
882*8975f5c5SAndroid Build Coastguard Worker         int firstPLSDrawBuffer = caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes - n;
883*8975f5c5SAndroid Build Coastguard Worker         int numAppDrawBuffers =
884*8975f5c5SAndroid Build Coastguard Worker             std::min(static_cast<int>(appDrawBuffers.size()), firstPLSDrawBuffer);
885*8975f5c5SAndroid Build Coastguard Worker         DrawBuffersArray<GLenum> plsDrawBuffers;
886*8975f5c5SAndroid Build Coastguard Worker         std::copy(appDrawBuffers.begin(), appDrawBuffers.begin() + numAppDrawBuffers,
887*8975f5c5SAndroid Build Coastguard Worker                   plsDrawBuffers.begin());
888*8975f5c5SAndroid Build Coastguard Worker         std::fill(plsDrawBuffers.begin() + numAppDrawBuffers,
889*8975f5c5SAndroid Build Coastguard Worker                   plsDrawBuffers.begin() + firstPLSDrawBuffer, GL_NONE);
890*8975f5c5SAndroid Build Coastguard Worker 
891*8975f5c5SAndroid Build Coastguard Worker         bool needsClear = false;
892*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei i = 0; i < n; ++i)
893*8975f5c5SAndroid Build Coastguard Worker         {
894*8975f5c5SAndroid Build Coastguard Worker             GLuint drawBufferIdx                = GetDrawBufferIdx(caps, i);
895*8975f5c5SAndroid Build Coastguard Worker             GLenum loadop                       = loadops[i];
896*8975f5c5SAndroid Build Coastguard Worker             const PixelLocalStoragePlane &plane = getPlane(i);
897*8975f5c5SAndroid Build Coastguard Worker             ASSERT(!plane.isDeinitialized());
898*8975f5c5SAndroid Build Coastguard Worker 
899*8975f5c5SAndroid Build Coastguard Worker             // Attach our PLS texture to the framebuffer. Validation should have already ensured
900*8975f5c5SAndroid Build Coastguard Worker             // nothing else was attached at this point.
901*8975f5c5SAndroid Build Coastguard Worker             GLenum colorAttachment = GL_COLOR_ATTACHMENT0 + drawBufferIdx;
902*8975f5c5SAndroid Build Coastguard Worker             ASSERT(!framebuffer->getAttachment(context, colorAttachment));
903*8975f5c5SAndroid Build Coastguard Worker             plane.attachToDrawFramebuffer(context, colorAttachment);
904*8975f5c5SAndroid Build Coastguard Worker             plsDrawBuffers[drawBufferIdx] = colorAttachment;
905*8975f5c5SAndroid Build Coastguard Worker 
906*8975f5c5SAndroid Build Coastguard Worker             needsClear = needsClear || (loadop != GL_LOAD_OP_LOAD_ANGLE);
907*8975f5c5SAndroid Build Coastguard Worker         }
908*8975f5c5SAndroid Build Coastguard Worker 
909*8975f5c5SAndroid Build Coastguard Worker         // Turn on the PLS draw buffers.
910*8975f5c5SAndroid Build Coastguard Worker         context->drawBuffers(caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes,
911*8975f5c5SAndroid Build Coastguard Worker                              plsDrawBuffers.data());
912*8975f5c5SAndroid Build Coastguard Worker 
913*8975f5c5SAndroid Build Coastguard Worker         // Clear the non-LOAD_OP_LOAD PLS planes now that their draw buffers are turned on.
914*8975f5c5SAndroid Build Coastguard Worker         if (needsClear)
915*8975f5c5SAndroid Build Coastguard Worker         {
916*8975f5c5SAndroid Build Coastguard Worker             ScopedDisableScissor scopedDisableScissor(context);
917*8975f5c5SAndroid Build Coastguard Worker             ClearBufferCommands clearBufferCommands(context);
918*8975f5c5SAndroid Build Coastguard Worker             for (GLsizei i = 0; i < n; ++i)
919*8975f5c5SAndroid Build Coastguard Worker             {
920*8975f5c5SAndroid Build Coastguard Worker                 GLenum loadop = loadops[i];
921*8975f5c5SAndroid Build Coastguard Worker                 if (loadop != GL_LOAD_OP_LOAD_ANGLE)
922*8975f5c5SAndroid Build Coastguard Worker                 {
923*8975f5c5SAndroid Build Coastguard Worker                     GLuint drawBufferIdx = GetDrawBufferIdx(caps, i);
924*8975f5c5SAndroid Build Coastguard Worker                     getPlane(i).issueClearCommand(&clearBufferCommands, drawBufferIdx, loadop);
925*8975f5c5SAndroid Build Coastguard Worker                 }
926*8975f5c5SAndroid Build Coastguard Worker             }
927*8975f5c5SAndroid Build Coastguard Worker         }
928*8975f5c5SAndroid Build Coastguard Worker 
929*8975f5c5SAndroid Build Coastguard Worker         if (!context->getExtensions().shaderPixelLocalStorageCoherentANGLE)
930*8975f5c5SAndroid Build Coastguard Worker         {
931*8975f5c5SAndroid Build Coastguard Worker             // Insert a barrier if we aren't coherent, since the textures may have been rendered to
932*8975f5c5SAndroid Build Coastguard Worker             // previously.
933*8975f5c5SAndroid Build Coastguard Worker             barrier(context);
934*8975f5c5SAndroid Build Coastguard Worker         }
935*8975f5c5SAndroid Build Coastguard Worker     }
936*8975f5c5SAndroid Build Coastguard Worker 
onEnd(Context * context,GLsizei n,const GLenum storeops[])937*8975f5c5SAndroid Build Coastguard Worker     void onEnd(Context *context, GLsizei n, const GLenum storeops[]) override
938*8975f5c5SAndroid Build Coastguard Worker     {
939*8975f5c5SAndroid Build Coastguard Worker         const Caps &caps = context->getCaps();
940*8975f5c5SAndroid Build Coastguard Worker 
941*8975f5c5SAndroid Build Coastguard Worker         // Invalidate the non-preserved PLS attachments.
942*8975f5c5SAndroid Build Coastguard Worker         DrawBuffersVector<GLenum> invalidateList;
943*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei i = n - 1; i >= 0; --i)
944*8975f5c5SAndroid Build Coastguard Worker         {
945*8975f5c5SAndroid Build Coastguard Worker             if (!getPlane(i).isActive())
946*8975f5c5SAndroid Build Coastguard Worker             {
947*8975f5c5SAndroid Build Coastguard Worker                 continue;
948*8975f5c5SAndroid Build Coastguard Worker             }
949*8975f5c5SAndroid Build Coastguard Worker             if (storeops[i] != GL_STORE_OP_STORE_ANGLE || getPlane(i).isMemoryless())
950*8975f5c5SAndroid Build Coastguard Worker             {
951*8975f5c5SAndroid Build Coastguard Worker                 int drawBufferIdx = GetDrawBufferIdx(caps, i);
952*8975f5c5SAndroid Build Coastguard Worker                 invalidateList.push_back(GL_COLOR_ATTACHMENT0 + drawBufferIdx);
953*8975f5c5SAndroid Build Coastguard Worker             }
954*8975f5c5SAndroid Build Coastguard Worker         }
955*8975f5c5SAndroid Build Coastguard Worker         if (!invalidateList.empty())
956*8975f5c5SAndroid Build Coastguard Worker         {
957*8975f5c5SAndroid Build Coastguard Worker             context->invalidateFramebuffer(GL_DRAW_FRAMEBUFFER,
958*8975f5c5SAndroid Build Coastguard Worker                                            static_cast<GLsizei>(invalidateList.size()),
959*8975f5c5SAndroid Build Coastguard Worker                                            invalidateList.data());
960*8975f5c5SAndroid Build Coastguard Worker         }
961*8975f5c5SAndroid Build Coastguard Worker 
962*8975f5c5SAndroid Build Coastguard Worker         for (GLsizei i = 0; i < n; ++i)
963*8975f5c5SAndroid Build Coastguard Worker         {
964*8975f5c5SAndroid Build Coastguard Worker             // Reset color attachments where PLS was attached. Validation should have already
965*8975f5c5SAndroid Build Coastguard Worker             // ensured nothing was attached at these points when we activated pixel local storage,
966*8975f5c5SAndroid Build Coastguard Worker             // and that nothing got attached during.
967*8975f5c5SAndroid Build Coastguard Worker             GLuint drawBufferIdx   = GetDrawBufferIdx(caps, i);
968*8975f5c5SAndroid Build Coastguard Worker             GLenum colorAttachment = GL_COLOR_ATTACHMENT0 + drawBufferIdx;
969*8975f5c5SAndroid Build Coastguard Worker             context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, colorAttachment, TextureTarget::_2D,
970*8975f5c5SAndroid Build Coastguard Worker                                           TextureID(), 0);
971*8975f5c5SAndroid Build Coastguard Worker         }
972*8975f5c5SAndroid Build Coastguard Worker 
973*8975f5c5SAndroid Build Coastguard Worker         // Restore the draw buffer state from before PLS was enabled.
974*8975f5c5SAndroid Build Coastguard Worker         context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
975*8975f5c5SAndroid Build Coastguard Worker                              mSavedDrawBuffers.data());
976*8975f5c5SAndroid Build Coastguard Worker         mSavedDrawBuffers.clear();
977*8975f5c5SAndroid Build Coastguard Worker     }
978*8975f5c5SAndroid Build Coastguard Worker 
onBarrier(Context * context)979*8975f5c5SAndroid Build Coastguard Worker     void onBarrier(Context *context) override { context->framebufferFetchBarrier(); }
980*8975f5c5SAndroid Build Coastguard Worker 
981*8975f5c5SAndroid Build Coastguard Worker   private:
GetDrawBufferIdx(const Caps & caps,GLuint plsPlaneIdx)982*8975f5c5SAndroid Build Coastguard Worker     static GLuint GetDrawBufferIdx(const Caps &caps, GLuint plsPlaneIdx)
983*8975f5c5SAndroid Build Coastguard Worker     {
984*8975f5c5SAndroid Build Coastguard Worker         // Bind the PLS attachments in reverse order from the rear. This way, the shader translator
985*8975f5c5SAndroid Build Coastguard Worker         // doesn't need to know how many planes are going to be active in order to figure out plane
986*8975f5c5SAndroid Build Coastguard Worker         // indices.
987*8975f5c5SAndroid Build Coastguard Worker         return caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes - plsPlaneIdx - 1;
988*8975f5c5SAndroid Build Coastguard Worker     }
989*8975f5c5SAndroid Build Coastguard Worker 
990*8975f5c5SAndroid Build Coastguard Worker     DrawBuffersVector<GLenum> mSavedDrawBuffers;
991*8975f5c5SAndroid Build Coastguard Worker };
992*8975f5c5SAndroid Build Coastguard Worker 
993*8975f5c5SAndroid Build Coastguard Worker }  // namespace
994*8975f5c5SAndroid Build Coastguard Worker 
Make(const Context * context)995*8975f5c5SAndroid Build Coastguard Worker std::unique_ptr<PixelLocalStorage> PixelLocalStorage::Make(const Context *context)
996*8975f5c5SAndroid Build Coastguard Worker {
997*8975f5c5SAndroid Build Coastguard Worker     const ShPixelLocalStorageOptions &plsOptions =
998*8975f5c5SAndroid Build Coastguard Worker         context->getImplementation()->getNativePixelLocalStorageOptions();
999*8975f5c5SAndroid Build Coastguard Worker     const Caps &caps = context->getState().getCaps();
1000*8975f5c5SAndroid Build Coastguard Worker     switch (plsOptions.type)
1001*8975f5c5SAndroid Build Coastguard Worker     {
1002*8975f5c5SAndroid Build Coastguard Worker         case ShPixelLocalStorageType::ImageLoadStore:
1003*8975f5c5SAndroid Build Coastguard Worker             return std::make_unique<PixelLocalStorageImageLoadStore>(plsOptions, caps);
1004*8975f5c5SAndroid Build Coastguard Worker         case ShPixelLocalStorageType::FramebufferFetch:
1005*8975f5c5SAndroid Build Coastguard Worker             return std::make_unique<PixelLocalStorageFramebufferFetch>(plsOptions, caps);
1006*8975f5c5SAndroid Build Coastguard Worker         default:
1007*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
1008*8975f5c5SAndroid Build Coastguard Worker             return nullptr;
1009*8975f5c5SAndroid Build Coastguard Worker     }
1010*8975f5c5SAndroid Build Coastguard Worker }
1011*8975f5c5SAndroid Build Coastguard Worker }  // namespace gl
1012