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 // It's important to keep the attachment enabled so that it's set in the corresponding
643 // MTLRenderPassAttachmentDescriptor. As the fragment shader does not have any output
644 // bound to this attachment, set the color write mask to all-disabled.
645 // Note that the PLS extension disallows simultaneously binding a single texture image
646 // to a PLS plane and attaching it to the draw framebuffer. Enabling this workaround on
647 // any other platform would yield incorrect results.
648 // This flag is set to true iff the framebuffer has an attachment 0 and it is enabled.
649 mHadColorAttachment0 = framebuffer->getDrawBufferMask().test(0);
650 if (!mHadColorAttachment0)
651 {
652 // Indexed color masks are always available on Metal.
653 ASSERT(context->getExtensions().drawBuffersIndexedAny());
654 // Remember the current draw buffer 0 color mask and set it to all-disabled.
655 state.getBlendStateExt().getColorMaskIndexed(
656 0, &mSavedColorMask[0], &mSavedColorMask[1], &mSavedColorMask[2],
657 &mSavedColorMask[3]);
658 ContextPrivateColorMaski(context->getMutablePrivateState(),
659 context->getMutablePrivateStateCache(), 0, false, false,
660 false, false);
661
662 // Remember the current draw buffer state so we can restore it during onEnd().
663 const DrawBuffersVector<GLenum> &appDrawBuffers =
664 framebuffer->getDrawBufferStates();
665 mSavedDrawBuffers.resize(appDrawBuffers.size());
666 std::copy(appDrawBuffers.begin(), appDrawBuffers.end(), mSavedDrawBuffers.begin());
667
668 // Turn on draw buffer 0.
669 if (mSavedDrawBuffers[0] != GL_COLOR_ATTACHMENT0)
670 {
671 GLenum drawBuffer0 = mSavedDrawBuffers[0];
672 mSavedDrawBuffers[0] = GL_COLOR_ATTACHMENT0;
673 context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
674 mSavedDrawBuffers.data());
675 mSavedDrawBuffers[0] = drawBuffer0;
676 }
677
678 // Attach one of the PLS textures to GL_COLOR_ATTACHMENT0.
679 getPlane(0).attachToDrawFramebuffer(context, GL_COLOR_ATTACHMENT0);
680 }
681 }
682 else
683 {
684 // Save the default framebuffer width/height so we can restore it during onEnd().
685 mSavedFramebufferDefaultWidth = framebuffer->getDefaultWidth();
686 mSavedFramebufferDefaultHeight = framebuffer->getDefaultHeight();
687
688 // Specify the framebuffer width/height explicitly in case we end up rendering
689 // exclusively to shader images.
690 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
691 plsExtents.width);
692 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
693 plsExtents.height);
694 }
695
696 // Guard GL state and bind a scratch framebuffer in case we need to reallocate or clear any
697 // PLS planes.
698 const size_t maxDrawBuffers = context->getCaps().maxDrawBuffers;
699 ScopedRestoreDrawFramebuffer ScopedRestoreDrawFramebuffer(context);
700 if (mScratchFramebufferForClearing.value == 0)
701 {
702 context->genFramebuffers(1, &mScratchFramebufferForClearing);
703 context->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mScratchFramebufferForClearing);
704 // Turn on all draw buffers on the scratch framebuffer for clearing.
705 DrawBuffersVector<GLenum> drawBuffers(maxDrawBuffers);
706 std::iota(drawBuffers.begin(), drawBuffers.end(), GL_COLOR_ATTACHMENT0);
707 context->drawBuffers(static_cast<int>(drawBuffers.size()), drawBuffers.data());
708 }
709 else
710 {
711 context->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mScratchFramebufferForClearing);
712 }
713 ScopedDisableScissor scopedDisableScissor(context);
714
715 // Bind and clear the PLS planes.
716 size_t maxClearedAttachments = 0;
717 for (GLsizei i = 0; i < n;)
718 {
719 DrawBuffersVector<int> pendingClears;
720 for (; pendingClears.size() < maxDrawBuffers && i < n; ++i)
721 {
722 GLenum loadop = loadops[i];
723 const PixelLocalStoragePlane &plane = getPlane(i);
724 plane.bindToImage(context, i, !mPLSOptions.supportsNativeRGBA8ImageFormats);
725 if (loadop == GL_LOAD_OP_ZERO_ANGLE || loadop == GL_LOAD_OP_CLEAR_ANGLE)
726 {
727 plane.attachToDrawFramebuffer(
728 context, GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(pendingClears.size()));
729 pendingClears.push_back(i); // Defer the clear for later.
730 }
731 }
732 // Clear in batches in order to be more efficient with GL state.
733 ScopedEnableColorMask scopedEnableColorMask(context,
734 static_cast<int>(pendingClears.size()));
735 ClearBufferCommands clearBufferCommands(context);
736 for (size_t drawBufferIdx = 0; drawBufferIdx < pendingClears.size(); ++drawBufferIdx)
737 {
738 int plsIdx = pendingClears[drawBufferIdx];
739 getPlane(plsIdx).issueClearCommand(
740 &clearBufferCommands, static_cast<int>(drawBufferIdx), loadops[plsIdx]);
741 }
742 maxClearedAttachments = std::max(maxClearedAttachments, pendingClears.size());
743 }
744
745 // Detach the cleared PLS textures from the scratch framebuffer.
746 for (size_t i = 0; i < maxClearedAttachments; ++i)
747 {
748 context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER,
749 GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(i),
750 TextureTarget::_2D, TextureID(), 0);
751 }
752
753 // Unlike other barriers, GL_SHADER_IMAGE_ACCESS_BARRIER_BIT also synchronizes all types of
754 // memory accesses that happened before the barrier:
755 //
756 // SHADER_IMAGE_ACCESS_BARRIER_BIT: Memory accesses using shader built-in image load and
757 // store functions issued after the barrier will reflect data written by shaders prior to
758 // the barrier. Additionally, image stores issued after the barrier will not execute until
759 // all memory accesses (e.g., loads, stores, texture fetches, vertex fetches) initiated
760 // prior to the barrier complete.
761 //
762 // So we don't any barriers other than GL_SHADER_IMAGE_ACCESS_BARRIER_BIT during begin().
763 context->memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
764 }
765
onEnd(Context * context,const GLenum storeops[])766 void onEnd(Context *context, const GLenum storeops[]) override
767 {
768 GLsizei n = context->getState().getPixelLocalStorageActivePlanes();
769
770 // Restore the image bindings. Since glBindImageTexture and any commands that modify
771 // textures are banned while PLS is active, these will all still be alive and valid.
772 ASSERT(mSavedImageBindings.size() == static_cast<size_t>(n));
773 for (GLuint unit = 0; unit < mSavedImageBindings.size(); ++unit)
774 {
775 ImageUnit &binding = mSavedImageBindings[unit];
776 context->bindImageTexture(unit, binding.texture.id(), binding.level, binding.layered,
777 binding.layer, binding.access, binding.format);
778
779 // BindingPointers have to be explicitly cleaned up.
780 binding.texture.set(context, nullptr);
781 }
782 mSavedImageBindings.clear();
783
784 if (mPLSOptions.renderPassNeedsAMDRasterOrderGroupsWorkaround)
785 {
786 if (!mHadColorAttachment0)
787 {
788 // Detach the PLS texture we attached to GL_COLOR_ATTACHMENT0.
789 context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
790 TextureTarget::_2D, TextureID(), 0);
791
792 // Restore the draw buffer state from before PLS was enabled.
793 if (mSavedDrawBuffers[0] != GL_COLOR_ATTACHMENT0)
794 {
795 context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
796 mSavedDrawBuffers.data());
797 }
798 mSavedDrawBuffers.clear();
799
800 // Restore the draw buffer 0 color mask.
801 ContextPrivateColorMaski(
802 context->getMutablePrivateState(), context->getMutablePrivateStateCache(), 0,
803 mSavedColorMask[0], mSavedColorMask[1], mSavedColorMask[2], mSavedColorMask[3]);
804 }
805 }
806 else
807 {
808 // Restore the default framebuffer width/height.
809 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
810 mSavedFramebufferDefaultWidth);
811 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
812 mSavedFramebufferDefaultHeight);
813 }
814
815 // We need ALL_BARRIER_BITS during end() because GL_SHADER_IMAGE_ACCESS_BARRIER_BIT doesn't
816 // synchronize all types of memory accesses that can happen after the barrier.
817 context->memoryBarrier(GL_ALL_BARRIER_BITS);
818 }
819
onBarrier(Context * context)820 void onBarrier(Context *context) override
821 {
822 context->memoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
823 }
824
825 private:
826 // D3D and ES require us to pack all PLS formats into r32f, r32i, or r32ui images.
827 FramebufferID mScratchFramebufferForClearing{};
828
829 // Saved values to restore during onEnd().
830 std::vector<ImageUnit> mSavedImageBindings;
831 // If mPLSOptions.plsRenderPassNeedsColorAttachmentWorkaround.
832 bool mHadColorAttachment0;
833 std::array<bool, 4> mSavedColorMask;
834 DrawBuffersVector<GLenum> mSavedDrawBuffers;
835 // If !mPLSOptions.plsRenderPassNeedsColorAttachmentWorkaround.
836 GLint mSavedFramebufferDefaultWidth;
837 GLint mSavedFramebufferDefaultHeight;
838 };
839
840 // Implements pixel local storage via framebuffer fetch.
841 class PixelLocalStorageFramebufferFetch : public PixelLocalStorage
842 {
843 public:
PixelLocalStorageFramebufferFetch(const ShPixelLocalStorageOptions & plsOptions,const Caps & caps)844 PixelLocalStorageFramebufferFetch(const ShPixelLocalStorageOptions &plsOptions,
845 const Caps &caps)
846 : PixelLocalStorage(plsOptions, caps)
847 {
848 ASSERT(mPLSOptions.type == ShPixelLocalStorageType::FramebufferFetch);
849 }
850
onContextObjectsLost()851 void onContextObjectsLost() override {}
852
onDeleteContextObjects(Context *)853 void onDeleteContextObjects(Context *) override {}
854
onBegin(Context * context,GLsizei n,const GLenum loadops[],Extents plsExtents)855 void onBegin(Context *context, GLsizei n, const GLenum loadops[], Extents plsExtents) override
856 {
857 const State &state = context->getState();
858 const Caps &caps = context->getCaps();
859 Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
860 const DrawBuffersVector<GLenum> &appDrawBuffers = framebuffer->getDrawBufferStates();
861
862 // Remember the current draw buffer state so we can restore it during onEnd().
863 mSavedDrawBuffers.resize(appDrawBuffers.size());
864 std::copy(appDrawBuffers.begin(), appDrawBuffers.end(), mSavedDrawBuffers.begin());
865
866 // Set up new draw buffers for PLS.
867 int firstPLSDrawBuffer = caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes - n;
868 int numAppDrawBuffers =
869 std::min(static_cast<int>(appDrawBuffers.size()), firstPLSDrawBuffer);
870 DrawBuffersArray<GLenum> plsDrawBuffers;
871 std::copy(appDrawBuffers.begin(), appDrawBuffers.begin() + numAppDrawBuffers,
872 plsDrawBuffers.begin());
873 std::fill(plsDrawBuffers.begin() + numAppDrawBuffers,
874 plsDrawBuffers.begin() + firstPLSDrawBuffer, GL_NONE);
875
876 mBlendsToReEnable.reset();
877 mColorMasksToRestore.reset();
878 bool needsClear = false;
879
880 bool hasIndexedBlendAndColorMask = context->getExtensions().drawBuffersIndexedAny();
881 if (!hasIndexedBlendAndColorMask)
882 {
883 // We don't have indexed blend and color mask control. Disable them globally. (This also
884 // means the app can't have its own draw buffers while PLS is active.)
885 ASSERT(caps.maxColorAttachmentsWithActivePixelLocalStorage == 0);
886 if (state.isBlendEnabled())
887 {
888 ContextPrivateDisable(context->getMutablePrivateState(),
889 context->getMutablePrivateStateCache(), GL_BLEND);
890 mBlendsToReEnable.set(0);
891 }
892 std::array<bool, 4> &mask = mSavedColorMasks[0];
893 state.getBlendStateExt().getColorMaskIndexed(0, &mask[0], &mask[1], &mask[2], &mask[3]);
894 if (!(mask[0] && mask[1] && mask[2] && mask[3]))
895 {
896 ContextPrivateColorMask(context->getMutablePrivateState(),
897 context->getMutablePrivateStateCache(), GL_TRUE, GL_TRUE,
898 GL_TRUE, GL_TRUE);
899 mColorMasksToRestore.set(0);
900 }
901 }
902
903 for (GLsizei i = 0; i < n; ++i)
904 {
905 GLuint drawBufferIdx = GetDrawBufferIdx(caps, i);
906 GLenum loadop = loadops[i];
907 const PixelLocalStoragePlane &plane = getPlane(i);
908 ASSERT(!plane.isDeinitialized());
909
910 // Attach our PLS texture to the framebuffer. Validation should have already ensured
911 // nothing else was attached at this point.
912 GLenum colorAttachment = GL_COLOR_ATTACHMENT0 + drawBufferIdx;
913 ASSERT(!framebuffer->getAttachment(context, colorAttachment));
914 plane.attachToDrawFramebuffer(context, colorAttachment);
915 plsDrawBuffers[drawBufferIdx] = colorAttachment;
916
917 if (hasIndexedBlendAndColorMask)
918 {
919 // Ensure blend and color mask are disabled for this draw buffer.
920 if (state.isBlendEnabledIndexed(drawBufferIdx))
921 {
922 ContextPrivateDisablei(context->getMutablePrivateState(),
923 context->getMutablePrivateStateCache(), GL_BLEND,
924 drawBufferIdx);
925 mBlendsToReEnable.set(drawBufferIdx);
926 }
927 std::array<bool, 4> &mask = mSavedColorMasks[drawBufferIdx];
928 state.getBlendStateExt().getColorMaskIndexed(drawBufferIdx, &mask[0], &mask[1],
929 &mask[2], &mask[3]);
930 if (!(mask[0] && mask[1] && mask[2] && mask[3]))
931 {
932 ContextPrivateColorMaski(context->getMutablePrivateState(),
933 context->getMutablePrivateStateCache(), drawBufferIdx,
934 GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
935 mColorMasksToRestore.set(drawBufferIdx);
936 }
937 }
938
939 needsClear = needsClear || (loadop != GL_LOAD_OP_LOAD_ANGLE);
940 }
941
942 // Turn on the PLS draw buffers.
943 context->drawBuffers(caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes,
944 plsDrawBuffers.data());
945
946 // Clear the non-LOAD_OP_LOAD PLS planes now that their draw buffers are turned on.
947 if (needsClear)
948 {
949 ScopedDisableScissor scopedDisableScissor(context);
950 ClearBufferCommands clearBufferCommands(context);
951 for (GLsizei i = 0; i < n; ++i)
952 {
953 GLenum loadop = loadops[i];
954 if (loadop != GL_LOAD_OP_LOAD_ANGLE)
955 {
956 GLuint drawBufferIdx = GetDrawBufferIdx(caps, i);
957 getPlane(i).issueClearCommand(&clearBufferCommands, drawBufferIdx, loadop);
958 }
959 }
960 }
961
962 if (!context->getExtensions().shaderPixelLocalStorageCoherentANGLE)
963 {
964 // Insert a barrier if we aren't coherent, since the textures may have been rendered to
965 // previously.
966 barrier(context);
967 }
968 }
969
onEnd(Context * context,const GLenum storeops[])970 void onEnd(Context *context, const GLenum storeops[]) override
971 {
972 GLsizei n = context->getState().getPixelLocalStorageActivePlanes();
973 const Caps &caps = context->getCaps();
974
975 // Invalidate the non-preserved PLS attachments.
976 DrawBuffersVector<GLenum> invalidateList;
977 for (GLsizei i = n - 1; i >= 0; --i)
978 {
979 if (!getPlane(i).isActive())
980 {
981 continue;
982 }
983 if (storeops[i] != GL_STORE_OP_STORE_ANGLE || getPlane(i).isMemoryless())
984 {
985 int drawBufferIdx = GetDrawBufferIdx(caps, i);
986 invalidateList.push_back(GL_COLOR_ATTACHMENT0 + drawBufferIdx);
987 }
988 }
989 if (!invalidateList.empty())
990 {
991 context->invalidateFramebuffer(GL_DRAW_FRAMEBUFFER,
992 static_cast<GLsizei>(invalidateList.size()),
993 invalidateList.data());
994 }
995
996 bool hasIndexedBlendAndColorMask = context->getExtensions().drawBuffersIndexedAny();
997 if (!hasIndexedBlendAndColorMask)
998 {
999 // Restore global blend and color mask. Validation should have ensured these didn't
1000 // change while pixel local storage was active.
1001 if (mBlendsToReEnable[0])
1002 {
1003 ContextPrivateEnable(context->getMutablePrivateState(),
1004 context->getMutablePrivateStateCache(), GL_BLEND);
1005 }
1006 if (mColorMasksToRestore[0])
1007 {
1008 const std::array<bool, 4> &mask = mSavedColorMasks[0];
1009 ContextPrivateColorMask(context->getMutablePrivateState(),
1010 context->getMutablePrivateStateCache(), mask[0], mask[1],
1011 mask[2], mask[3]);
1012 }
1013 }
1014
1015 for (GLsizei i = 0; i < n; ++i)
1016 {
1017 // Reset color attachments where PLS was attached. Validation should have already
1018 // ensured nothing was attached at these points when we activated pixel local storage,
1019 // and that nothing got attached during.
1020 GLuint drawBufferIdx = GetDrawBufferIdx(caps, i);
1021 GLenum colorAttachment = GL_COLOR_ATTACHMENT0 + drawBufferIdx;
1022 context->framebufferTexture2D(GL_DRAW_FRAMEBUFFER, colorAttachment, TextureTarget::_2D,
1023 TextureID(), 0);
1024
1025 if (hasIndexedBlendAndColorMask)
1026 {
1027 // Restore this draw buffer's blend and color mask. Validation should have ensured
1028 // these did not change while pixel local storage was active.
1029 if (mBlendsToReEnable[drawBufferIdx])
1030 {
1031 ContextPrivateEnablei(context->getMutablePrivateState(),
1032 context->getMutablePrivateStateCache(), GL_BLEND,
1033 drawBufferIdx);
1034 }
1035 if (mColorMasksToRestore[drawBufferIdx])
1036 {
1037 const std::array<bool, 4> &mask = mSavedColorMasks[drawBufferIdx];
1038 ContextPrivateColorMaski(context->getMutablePrivateState(),
1039 context->getMutablePrivateStateCache(), drawBufferIdx,
1040 mask[0], mask[1], mask[2], mask[3]);
1041 }
1042 }
1043 }
1044
1045 // Restore the draw buffer state from before PLS was enabled.
1046 context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
1047 mSavedDrawBuffers.data());
1048 mSavedDrawBuffers.clear();
1049 }
1050
onBarrier(Context * context)1051 void onBarrier(Context *context) override { context->framebufferFetchBarrier(); }
1052
1053 private:
GetDrawBufferIdx(const Caps & caps,GLuint plsPlaneIdx)1054 static GLuint GetDrawBufferIdx(const Caps &caps, GLuint plsPlaneIdx)
1055 {
1056 // Bind the PLS attachments in reverse order from the rear. This way, the shader translator
1057 // doesn't need to know how many planes are going to be active in order to figure out plane
1058 // indices.
1059 return caps.maxCombinedDrawBuffersAndPixelLocalStoragePlanes - plsPlaneIdx - 1;
1060 }
1061
1062 DrawBuffersVector<GLenum> mSavedDrawBuffers;
1063 DrawBufferMask mBlendsToReEnable;
1064 DrawBufferMask mColorMasksToRestore;
1065 DrawBuffersArray<std::array<bool, 4>> mSavedColorMasks;
1066 };
1067
1068 // Implements ANGLE_shader_pixel_local_storage directly via EXT_shader_pixel_local_storage.
1069 class PixelLocalStorageEXT : public PixelLocalStorage
1070 {
1071 public:
PixelLocalStorageEXT(const ShPixelLocalStorageOptions & plsOptions,const Caps & caps)1072 PixelLocalStorageEXT(const ShPixelLocalStorageOptions &plsOptions, const Caps &caps)
1073 : PixelLocalStorage(plsOptions, caps)
1074 {
1075 ASSERT(mPLSOptions.type == ShPixelLocalStorageType::PixelLocalStorageEXT);
1076 }
1077
1078 private:
onContextObjectsLost()1079 void onContextObjectsLost() override {}
1080
onDeleteContextObjects(Context *)1081 void onDeleteContextObjects(Context *) override {}
1082
onBegin(Context * context,GLsizei n,const GLenum loadops[],Extents plsExtents)1083 void onBegin(Context *context, GLsizei n, const GLenum loadops[], Extents plsExtents) override
1084 {
1085 const State &state = context->getState();
1086 Framebuffer *framebuffer = state.getDrawFramebuffer();
1087
1088 // Remember the current draw buffer state so we can restore it during onEnd().
1089 const DrawBuffersVector<GLenum> &appDrawBuffers = framebuffer->getDrawBufferStates();
1090 mSavedDrawBuffers.resize(appDrawBuffers.size());
1091 std::copy(appDrawBuffers.begin(), appDrawBuffers.end(), mSavedDrawBuffers.begin());
1092
1093 // Turn off draw buffers.
1094 context->drawBuffers(0, nullptr);
1095
1096 // Save the default framebuffer width/height so we can restore it during onEnd().
1097 mSavedFramebufferDefaultWidth = framebuffer->getDefaultWidth();
1098 mSavedFramebufferDefaultHeight = framebuffer->getDefaultHeight();
1099
1100 // Specify the framebuffer width/height explicitly since we don't use color attachments in
1101 // this mode.
1102 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
1103 plsExtents.width);
1104 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
1105 plsExtents.height);
1106
1107 context->drawPixelLocalStorageEXTEnable(n, getPlanes(), loadops);
1108
1109 memcpy(mActiveLoadOps.data(), loadops, sizeof(GLenum) * n);
1110 }
1111
onEnd(Context * context,const GLenum storeops[])1112 void onEnd(Context *context, const GLenum storeops[]) override
1113 {
1114 context->drawPixelLocalStorageEXTDisable(getPlanes(), storeops);
1115
1116 // Restore the default framebuffer width/height.
1117 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
1118 mSavedFramebufferDefaultWidth);
1119 context->framebufferParameteri(GL_DRAW_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
1120 mSavedFramebufferDefaultHeight);
1121
1122 // Restore the draw buffer state from before PLS was enabled.
1123 context->drawBuffers(static_cast<GLsizei>(mSavedDrawBuffers.size()),
1124 mSavedDrawBuffers.data());
1125 mSavedDrawBuffers.clear();
1126 }
1127
onBarrier(Context * context)1128 void onBarrier(Context *context) override { UNREACHABLE(); }
1129
1130 // Saved values to restore during onEnd().
1131 GLint mSavedFramebufferDefaultWidth;
1132 GLint mSavedFramebufferDefaultHeight;
1133 DrawBuffersVector<GLenum> mSavedDrawBuffers;
1134
1135 std::array<GLenum, IMPLEMENTATION_MAX_PIXEL_LOCAL_STORAGE_PLANES> mActiveLoadOps;
1136 };
1137 } // namespace
1138
Make(const Context * context)1139 std::unique_ptr<PixelLocalStorage> PixelLocalStorage::Make(const Context *context)
1140 {
1141 const ShPixelLocalStorageOptions &plsOptions =
1142 context->getImplementation()->getNativePixelLocalStorageOptions();
1143 const Caps &caps = context->getState().getCaps();
1144 switch (plsOptions.type)
1145 {
1146 case ShPixelLocalStorageType::ImageLoadStore:
1147 return std::make_unique<PixelLocalStorageImageLoadStore>(plsOptions, caps);
1148 case ShPixelLocalStorageType::FramebufferFetch:
1149 return std::make_unique<PixelLocalStorageFramebufferFetch>(plsOptions, caps);
1150 case ShPixelLocalStorageType::PixelLocalStorageEXT:
1151 return std::make_unique<PixelLocalStorageEXT>(plsOptions, caps);
1152 default:
1153 UNREACHABLE();
1154 return nullptr;
1155 }
1156 }
1157 } // namespace gl
1158