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