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