xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/FramebufferGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2015 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 // FramebufferGL.cpp: Implements the class methods for FramebufferGL.
8 
9 #include "libANGLE/renderer/gl/FramebufferGL.h"
10 
11 #include "common/bitset_utils.h"
12 #include "common/debug.h"
13 #include "libANGLE/ErrorStrings.h"
14 #include "libANGLE/FramebufferAttachment.h"
15 #include "libANGLE/State.h"
16 #include "libANGLE/angletypes.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/queryconversions.h"
19 #include "libANGLE/renderer/ContextImpl.h"
20 #include "libANGLE/renderer/gl/BlitGL.h"
21 #include "libANGLE/renderer/gl/ClearMultiviewGL.h"
22 #include "libANGLE/renderer/gl/ContextGL.h"
23 #include "libANGLE/renderer/gl/FunctionsGL.h"
24 #include "libANGLE/renderer/gl/RenderbufferGL.h"
25 #include "libANGLE/renderer/gl/StateManagerGL.h"
26 #include "libANGLE/renderer/gl/TextureGL.h"
27 #include "libANGLE/renderer/gl/formatutilsgl.h"
28 #include "libANGLE/renderer/gl/renderergl_utils.h"
29 #include "platform/PlatformMethods.h"
30 #include "platform/autogen/FeaturesGL_autogen.h"
31 
32 using namespace gl;
33 using angle::CheckedNumeric;
34 
35 namespace rx
36 {
37 
38 namespace
39 {
40 
41 struct BlitFramebufferBounds
42 {
43     gl::Rectangle sourceBounds;
44     gl::Rectangle sourceRegion;
45 
46     gl::Rectangle destBounds;
47     gl::Rectangle destRegion;
48 
49     bool xFlipped;
50     bool yFlipped;
51 };
52 
GetBlitFramebufferBounds(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea)53 static BlitFramebufferBounds GetBlitFramebufferBounds(const gl::Context *context,
54                                                       const gl::Rectangle &sourceArea,
55                                                       const gl::Rectangle &destArea)
56 {
57     BlitFramebufferBounds bounds;
58 
59     const Framebuffer *sourceFramebuffer = context->getState().getReadFramebuffer();
60     const Framebuffer *destFramebuffer   = context->getState().getDrawFramebuffer();
61 
62     gl::Extents readSize = sourceFramebuffer->getExtents();
63     gl::Extents drawSize = destFramebuffer->getExtents();
64 
65     bounds.sourceBounds = gl::Rectangle(0, 0, readSize.width, readSize.height);
66     bounds.sourceRegion = sourceArea.removeReversal();
67 
68     bounds.destBounds = gl::Rectangle(0, 0, drawSize.width, drawSize.height);
69     bounds.destRegion = destArea.removeReversal();
70 
71     bounds.xFlipped = sourceArea.isReversedX() != destArea.isReversedX();
72     bounds.yFlipped = sourceArea.isReversedY() != destArea.isReversedY();
73 
74     return bounds;
75 }
76 
BindFramebufferAttachment(const FunctionsGL * functions,GLenum attachmentPoint,const FramebufferAttachment * attachment,const angle::FeaturesGL & features)77 void BindFramebufferAttachment(const FunctionsGL *functions,
78                                GLenum attachmentPoint,
79                                const FramebufferAttachment *attachment,
80                                const angle::FeaturesGL &features)
81 {
82     if (attachment)
83     {
84         if (attachment->type() == GL_TEXTURE)
85         {
86             const Texture *texture     = attachment->getTexture();
87             const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
88 
89             if (texture->getType() == TextureType::_2D ||
90                 texture->getType() == TextureType::_2DMultisample ||
91                 texture->getType() == TextureType::Rectangle ||
92                 texture->getType() == TextureType::External)
93             {
94                 if (attachment->isRenderToTexture())
95                 {
96                     if (functions->framebufferTexture2DMultisampleEXT)
97                     {
98                         functions->framebufferTexture2DMultisampleEXT(
99                             GL_FRAMEBUFFER, attachmentPoint, ToGLenum(texture->getType()),
100                             textureGL->getTextureID(), attachment->mipLevel(),
101                             attachment->getSamples());
102                     }
103                     else
104                     {
105                         ASSERT(functions->framebufferTexture2DMultisampleIMG);
106                         functions->framebufferTexture2DMultisampleIMG(
107                             GL_FRAMEBUFFER, attachmentPoint, ToGLenum(texture->getType()),
108                             textureGL->getTextureID(), attachment->mipLevel(),
109                             attachment->getSamples());
110                     }
111                 }
112                 else
113                 {
114                     functions->framebufferTexture2D(
115                         GL_FRAMEBUFFER, attachmentPoint, ToGLenum(texture->getType()),
116                         textureGL->getTextureID(), attachment->mipLevel());
117                 }
118             }
119             else if (attachment->isLayered())
120             {
121                 TextureType textureType = texture->getType();
122                 ASSERT(textureType == TextureType::_2DArray || textureType == TextureType::_3D ||
123                        textureType == TextureType::CubeMap ||
124                        textureType == TextureType::_2DMultisampleArray ||
125                        textureType == TextureType::CubeMapArray);
126                 functions->framebufferTexture(GL_FRAMEBUFFER, attachmentPoint,
127                                               textureGL->getTextureID(), attachment->mipLevel());
128             }
129             else if (texture->getType() == TextureType::CubeMap)
130             {
131                 functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint,
132                                                 ToGLenum(attachment->cubeMapFace()),
133                                                 textureGL->getTextureID(), attachment->mipLevel());
134             }
135             else if (texture->getType() == TextureType::_2DArray ||
136                      texture->getType() == TextureType::_3D ||
137                      texture->getType() == TextureType::_2DMultisampleArray ||
138                      texture->getType() == TextureType::CubeMapArray)
139             {
140                 if (attachment->isMultiview())
141                 {
142                     ASSERT(functions->framebufferTexture);
143                     functions->framebufferTexture(GL_FRAMEBUFFER, attachmentPoint,
144                                                   textureGL->getTextureID(),
145                                                   attachment->mipLevel());
146                 }
147                 else
148                 {
149                     functions->framebufferTextureLayer(GL_FRAMEBUFFER, attachmentPoint,
150                                                        textureGL->getTextureID(),
151                                                        attachment->mipLevel(), attachment->layer());
152                 }
153             }
154             else
155             {
156                 UNREACHABLE();
157             }
158         }
159         else if (attachment->type() == GL_RENDERBUFFER)
160         {
161             const Renderbuffer *renderbuffer     = attachment->getRenderbuffer();
162             const RenderbufferGL *renderbufferGL = GetImplAs<RenderbufferGL>(renderbuffer);
163 
164             if (features.alwaysUnbindFramebufferTexture2D.enabled)
165             {
166                 functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, 0,
167                                                 0);
168             }
169 
170             functions->framebufferRenderbuffer(GL_FRAMEBUFFER, attachmentPoint, GL_RENDERBUFFER,
171                                                renderbufferGL->getRenderbufferID());
172         }
173         else
174         {
175             UNREACHABLE();
176         }
177     }
178     else
179     {
180         // Unbind this attachment
181         functions->framebufferTexture2D(GL_FRAMEBUFFER, attachmentPoint, GL_TEXTURE_2D, 0, 0);
182     }
183 }
184 
AreAllLayersActive(const FramebufferAttachment & attachment)185 bool AreAllLayersActive(const FramebufferAttachment &attachment)
186 {
187     int baseViewIndex = attachment.getBaseViewIndex();
188     if (baseViewIndex != 0)
189     {
190         return false;
191     }
192     const ImageIndex &imageIndex = attachment.getTextureImageIndex();
193     int numLayers                = static_cast<int>(
194         attachment.getTexture()->getDepth(imageIndex.getTarget(), imageIndex.getLevelIndex()));
195     return (attachment.getNumViews() == numLayers);
196 }
197 
RequiresMultiviewClear(const FramebufferState & state,bool scissorTestEnabled)198 bool RequiresMultiviewClear(const FramebufferState &state, bool scissorTestEnabled)
199 {
200     // Get one attachment and check whether all layers are attached.
201     const FramebufferAttachment *attachment = nullptr;
202     bool allTextureArraysAreFullyAttached   = true;
203     for (const FramebufferAttachment &colorAttachment : state.getColorAttachments())
204     {
205         if (colorAttachment.isAttached())
206         {
207             if (!colorAttachment.isMultiview())
208             {
209                 return false;
210             }
211             attachment = &colorAttachment;
212             allTextureArraysAreFullyAttached =
213                 allTextureArraysAreFullyAttached && AreAllLayersActive(*attachment);
214         }
215     }
216 
217     const FramebufferAttachment *depthAttachment = state.getDepthAttachment();
218     if (depthAttachment)
219     {
220         if (!depthAttachment->isMultiview())
221         {
222             return false;
223         }
224         attachment = depthAttachment;
225         allTextureArraysAreFullyAttached =
226             allTextureArraysAreFullyAttached && AreAllLayersActive(*attachment);
227     }
228     const FramebufferAttachment *stencilAttachment = state.getStencilAttachment();
229     if (stencilAttachment)
230     {
231         if (!stencilAttachment->isMultiview())
232         {
233             return false;
234         }
235         attachment = stencilAttachment;
236         allTextureArraysAreFullyAttached =
237             allTextureArraysAreFullyAttached && AreAllLayersActive(*attachment);
238     }
239 
240     if (attachment == nullptr)
241     {
242         return false;
243     }
244     if (attachment->isMultiview())
245     {
246         // If all layers of each texture array are active, then there is no need to issue a
247         // special multiview clear.
248         return !allTextureArraysAreFullyAttached;
249     }
250     return false;
251 }
252 
IsEmulatedAlphaChannelTextureAttachment(const FramebufferAttachment * attachment)253 bool IsEmulatedAlphaChannelTextureAttachment(const FramebufferAttachment *attachment)
254 {
255     if (!attachment || attachment->type() != GL_TEXTURE)
256     {
257         return false;
258     }
259 
260     const Texture *texture     = attachment->getTexture();
261     const TextureGL *textureGL = GetImplAs<TextureGL>(texture);
262     return textureGL->hasEmulatedAlphaChannel(attachment->getTextureImageIndex());
263 }
264 
265 class [[nodiscard]] ScopedEXTTextureNorm16ReadbackWorkaround
266 {
267   public:
ScopedEXTTextureNorm16ReadbackWorkaround()268     ScopedEXTTextureNorm16ReadbackWorkaround()
269         : tmpPixels(nullptr), clientPixels(nullptr), enabled(false)
270     {}
271 
~ScopedEXTTextureNorm16ReadbackWorkaround()272     ~ScopedEXTTextureNorm16ReadbackWorkaround()
273     {
274         if (tmpPixels)
275         {
276             delete[] tmpPixels;
277         }
278     }
279 
Initialize(const gl::Context * context,const gl::Rectangle & area,GLenum originalReadFormat,GLenum format,GLenum type,GLuint skipBytes,GLuint rowBytes,GLuint pixelBytes,GLubyte * pixels)280     angle::Result Initialize(const gl::Context *context,
281                              const gl::Rectangle &area,
282                              GLenum originalReadFormat,
283                              GLenum format,
284                              GLenum type,
285                              GLuint skipBytes,
286                              GLuint rowBytes,
287                              GLuint pixelBytes,
288                              GLubyte *pixels)
289     {
290         // Separate from constructor as there may be checked math result exception that needs to
291         // early return
292         ASSERT(tmpPixels == nullptr);
293         ASSERT(clientPixels == nullptr);
294 
295         ContextGL *contextGL              = GetImplAs<ContextGL>(context);
296         const angle::FeaturesGL &features = GetFeaturesGL(context);
297 
298         enabled = features.readPixelsUsingImplementationColorReadFormatForNorm16.enabled &&
299                   type == GL_UNSIGNED_SHORT && originalReadFormat == GL_RGBA &&
300                   (format == GL_RED || format == GL_RG);
301 
302         clientPixels = pixels;
303 
304         if (enabled)
305         {
306             CheckedNumeric<GLuint> checkedRowBytes(rowBytes);
307             CheckedNumeric<GLuint> checkedRows(area.height);
308             CheckedNumeric<GLuint> checkedSkipBytes(skipBytes);
309             auto checkedAllocatedBytes = checkedSkipBytes + checkedRowBytes * checkedRows;
310             if (rowBytes < area.width * pixelBytes)
311             {
312                 checkedAllocatedBytes += area.width * pixelBytes - rowBytes;
313             }
314             ANGLE_CHECK_GL_MATH(contextGL, checkedAllocatedBytes.IsValid());
315             const GLuint allocatedBytes = checkedAllocatedBytes.ValueOrDie();
316             tmpPixels                   = new GLubyte[allocatedBytes];
317             memset(tmpPixels, 0, allocatedBytes);
318         }
319 
320         return angle::Result::Continue;
321     }
322 
Pixels() const323     GLubyte *Pixels() const { return tmpPixels ? tmpPixels : clientPixels; }
324 
IsEnabled() const325     bool IsEnabled() const { return enabled; }
326 
327   private:
328     // Temporarily allocated pixel readback buffer
329     GLubyte *tmpPixels;
330     // Client pixel array pointer passed to readPixels
331     GLubyte *clientPixels;
332 
333     bool enabled;
334 };
335 
336 // Workaround to rearrange pixels read by RED/RG to RGBA for RGBA/UNSIGNED_SHORT pixel type
337 // combination
RearrangeEXTTextureNorm16Pixels(const gl::Context * context,const gl::Rectangle & area,GLenum originalReadFormat,GLenum format,GLenum type,GLuint skipBytes,GLuint rowBytes,GLuint pixelBytes,const gl::PixelPackState & pack,GLubyte * clientPixels,GLubyte * tmpPixels)338 angle::Result RearrangeEXTTextureNorm16Pixels(const gl::Context *context,
339                                               const gl::Rectangle &area,
340                                               GLenum originalReadFormat,
341                                               GLenum format,
342                                               GLenum type,
343                                               GLuint skipBytes,
344                                               GLuint rowBytes,
345                                               GLuint pixelBytes,
346                                               const gl::PixelPackState &pack,
347                                               GLubyte *clientPixels,
348                                               GLubyte *tmpPixels)
349 {
350     ASSERT(tmpPixels != nullptr);
351     ASSERT(originalReadFormat == GL_RGBA);
352     ASSERT(format == GL_RED_EXT || format == GL_RG_EXT);
353     ASSERT(type == GL_UNSIGNED_SHORT);
354 
355     ContextGL *contextGL = GetImplAs<ContextGL>(context);
356 
357     const gl::InternalFormat &glFormatOriginal =
358         gl::GetInternalFormatInfo(originalReadFormat, type);
359 
360     GLuint originalReadFormatRowBytes = 0;
361     ANGLE_CHECK_GL_MATH(
362         contextGL, glFormatOriginal.computeRowPitch(type, area.width, pack.alignment,
363                                                     pack.rowLength, &originalReadFormatRowBytes));
364     GLuint originalReadFormatSkipBytes = 0;
365     ANGLE_CHECK_GL_MATH(contextGL,
366                         glFormatOriginal.computeSkipBytes(type, originalReadFormatRowBytes, 0, pack,
367                                                           false, &originalReadFormatSkipBytes));
368 
369     GLuint originalReadFormatPixelBytes = glFormatOriginal.computePixelBytes(type);
370     GLuint alphaChannelBytes            = glFormatOriginal.alphaBits / 8;
371 
372     ASSERT(originalReadFormatPixelBytes > pixelBytes);
373     ASSERT(originalReadFormatPixelBytes > alphaChannelBytes);
374     ASSERT(alphaChannelBytes != 0);
375     ASSERT(glFormatOriginal.alphaBits % 8 == 0);
376 
377     // Populating rearrangedPixels values from pixels
378     GLubyte *srcRowStart = tmpPixels;
379     GLubyte *dstRowStart = clientPixels;
380 
381     srcRowStart += skipBytes;
382     dstRowStart += originalReadFormatSkipBytes;
383 
384     for (GLint y = 0; y < area.height; ++y)
385     {
386         GLubyte *src = srcRowStart;
387         GLubyte *dst = dstRowStart;
388         for (GLint x = 0; x < area.width; ++x)
389         {
390             GLushort *srcPixel = reinterpret_cast<GLushort *>(src);
391             GLushort *dstPixel = reinterpret_cast<GLushort *>(dst);
392             dstPixel[0]        = srcPixel[0];
393             dstPixel[1]        = format == GL_RG ? srcPixel[1] : 0;
394             // Set other channel of RGBA to 0 (GB when format == GL_RED, B when format == GL_RG)
395             dstPixel[2] = 0;
396             // Set alpha channel to 1
397             dstPixel[3] = 0xFFFF;
398 
399             src += pixelBytes;
400             dst += originalReadFormatPixelBytes;
401         }
402 
403         srcRowStart += rowBytes;
404         dstRowStart += originalReadFormatRowBytes;
405     }
406 
407     return angle::Result::Continue;
408 }
409 
IsValidUnsignedShortReadPixelsFormat(GLenum readFormat,const gl::Context * context)410 bool IsValidUnsignedShortReadPixelsFormat(GLenum readFormat, const gl::Context *context)
411 {
412     return (readFormat == GL_RED) || (readFormat == GL_RG) || (readFormat == GL_RGBA) ||
413            ((readFormat == GL_DEPTH_COMPONENT) && (context->getExtensions().readDepthNV));
414 }
415 
416 // Returns true for all colors except
417 // - transparent/opaque black
418 // - transparent/opaque white
IsNonTrivialClearColor(const GLfloat * color)419 bool IsNonTrivialClearColor(const GLfloat *color)
420 {
421     return !(((color[0] == 0.0f && color[1] == 0.0f && color[2] == 0.0f) ||
422               (color[0] == 1.0f && color[1] == 1.0f && color[2] == 1.0f)) &&
423              (color[3] == 0.0f || color[3] == 1.0f));
424 }
425 
426 // Returns true for all colors except
427 // - (0, 0, 0, 0 or 1)
428 // - (1, 1, 1, 0 or 1)
IsNonTrivialClearColor(const GLuint * color)429 bool IsNonTrivialClearColor(const GLuint *color)
430 {
431     return !(((color[0] == 0 && color[1] == 0 && color[2] == 0) ||
432               (color[0] == 1 && color[1] == 1 && color[2] == 1)) &&
433              (color[3] == 0 || color[3] == 1));
434 }
435 
436 }  // namespace
437 
FramebufferGL(const gl::FramebufferState & data,GLuint id,bool emulatedAlpha)438 FramebufferGL::FramebufferGL(const gl::FramebufferState &data, GLuint id, bool emulatedAlpha)
439     : FramebufferImpl(data),
440       mFramebufferID(id),
441       mHasEmulatedAlphaAttachment(emulatedAlpha),
442       mAppliedEnabledDrawBuffers(1)
443 {
444     ASSERT((isDefault() && id == 0) || !isDefault());
445 }
446 
~FramebufferGL()447 FramebufferGL::~FramebufferGL()
448 {
449     ASSERT(mFramebufferID == 0);
450 }
451 
destroy(const gl::Context * context)452 void FramebufferGL::destroy(const gl::Context *context)
453 {
454     if (mFramebufferID)
455     {
456         ASSERT(!isDefault());
457         StateManagerGL *stateManager = GetStateManagerGL(context);
458         stateManager->deleteFramebuffer(mFramebufferID);
459         mFramebufferID = 0;
460     }
461 }
462 
discard(const gl::Context * context,size_t count,const GLenum * attachments)463 angle::Result FramebufferGL::discard(const gl::Context *context,
464                                      size_t count,
465                                      const GLenum *attachments)
466 {
467     // glInvalidateFramebuffer accepts the same enums as glDiscardFramebufferEXT
468     return invalidate(context, count, attachments);
469 }
470 
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)471 angle::Result FramebufferGL::invalidate(const gl::Context *context,
472                                         size_t count,
473                                         const GLenum *attachments)
474 {
475     const GLenum *finalAttachmentsPtr = attachments;
476 
477     std::vector<GLenum> modifiedAttachments;
478     if (modifyInvalidateAttachmentsForEmulatedDefaultFBO(count, attachments, &modifiedAttachments))
479     {
480         finalAttachmentsPtr = modifiedAttachments.data();
481     }
482 
483     const FunctionsGL *functions = GetFunctionsGL(context);
484     StateManagerGL *stateManager = GetStateManagerGL(context);
485 
486     // Since this function is just a hint, only call a native function if it exists.
487     if (functions->invalidateFramebuffer)
488     {
489         stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
490         functions->invalidateFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
491                                          finalAttachmentsPtr);
492     }
493     else if (functions->discardFramebufferEXT)
494     {
495         stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
496         functions->discardFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
497                                          finalAttachmentsPtr);
498     }
499 
500     return angle::Result::Continue;
501 }
502 
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)503 angle::Result FramebufferGL::invalidateSub(const gl::Context *context,
504                                            size_t count,
505                                            const GLenum *attachments,
506                                            const gl::Rectangle &area)
507 {
508 
509     const GLenum *finalAttachmentsPtr = attachments;
510 
511     std::vector<GLenum> modifiedAttachments;
512     if (modifyInvalidateAttachmentsForEmulatedDefaultFBO(count, attachments, &modifiedAttachments))
513     {
514         finalAttachmentsPtr = modifiedAttachments.data();
515     }
516 
517     const FunctionsGL *functions = GetFunctionsGL(context);
518     StateManagerGL *stateManager = GetStateManagerGL(context);
519 
520     // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is
521     // available.
522     if (functions->invalidateSubFramebuffer)
523     {
524         stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
525         functions->invalidateSubFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
526                                             finalAttachmentsPtr, area.x, area.y, area.width,
527                                             area.height);
528     }
529 
530     return angle::Result::Continue;
531 }
532 
clear(const gl::Context * context,GLbitfield mask)533 angle::Result FramebufferGL::clear(const gl::Context *context, GLbitfield mask)
534 {
535     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
536     const FunctionsGL *functions = GetFunctionsGL(context);
537     StateManagerGL *stateManager = GetStateManagerGL(context);
538 
539     syncClearState(context, mask);
540     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
541 
542     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
543     {
544         functions->clear(mask);
545     }
546     else
547     {
548         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
549         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
550                                             ClearMultiviewGL::ClearCommandType::Clear, mask,
551                                             GL_NONE, 0, nullptr, 0.0f, 0);
552     }
553 
554     contextGL->markWorkSubmitted();
555 
556     // Perform cheaper checks first, relying on short-circuiting
557     if ((mask & GL_COLOR_BUFFER_BIT) != 0 && mState.getEnabledDrawBuffers().hasGaps() &&
558         GetFeaturesGL(context).clearsWithGapsNeedFlush.enabled &&
559         IsNonTrivialClearColor(context->getState().getColorClearValue().data()))
560     {
561         return contextGL->flush(context);
562     }
563 
564     return angle::Result::Continue;
565 }
566 
clearBufferfv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)567 angle::Result FramebufferGL::clearBufferfv(const gl::Context *context,
568                                            GLenum buffer,
569                                            GLint drawbuffer,
570                                            const GLfloat *values)
571 {
572     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
573     const FunctionsGL *functions = GetFunctionsGL(context);
574     StateManagerGL *stateManager = GetStateManagerGL(context);
575 
576     syncClearBufferState(context, buffer, drawbuffer);
577     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
578 
579     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
580     {
581         functions->clearBufferfv(buffer, drawbuffer, values);
582     }
583     else
584     {
585         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
586         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
587                                             ClearMultiviewGL::ClearCommandType::ClearBufferfv,
588                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
589                                             reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
590     }
591 
592     contextGL->markWorkSubmitted();
593 
594     // Perform cheaper checks first, relying on short-circuiting
595     if (buffer == GL_COLOR && mState.getEnabledDrawBuffers().hasGaps() &&
596         GetFeaturesGL(context).clearsWithGapsNeedFlush.enabled && IsNonTrivialClearColor(values))
597     {
598         return contextGL->flush(context);
599     }
600 
601     return angle::Result::Continue;
602 }
603 
clearBufferuiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)604 angle::Result FramebufferGL::clearBufferuiv(const gl::Context *context,
605                                             GLenum buffer,
606                                             GLint drawbuffer,
607                                             const GLuint *values)
608 {
609     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
610     const FunctionsGL *functions = GetFunctionsGL(context);
611     StateManagerGL *stateManager = GetStateManagerGL(context);
612 
613     syncClearBufferState(context, buffer, drawbuffer);
614     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
615 
616     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
617     {
618         functions->clearBufferuiv(buffer, drawbuffer, values);
619     }
620     else
621     {
622         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
623         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
624                                             ClearMultiviewGL::ClearCommandType::ClearBufferuiv,
625                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
626                                             reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
627     }
628 
629     contextGL->markWorkSubmitted();
630 
631     // Perform cheaper checks first, relying on short-circuiting
632     if (mState.getEnabledDrawBuffers().hasGaps() &&
633         GetFeaturesGL(context).clearsWithGapsNeedFlush.enabled && IsNonTrivialClearColor(values))
634     {
635         return contextGL->flush(context);
636     }
637 
638     return angle::Result::Continue;
639 }
640 
clearBufferiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)641 angle::Result FramebufferGL::clearBufferiv(const gl::Context *context,
642                                            GLenum buffer,
643                                            GLint drawbuffer,
644                                            const GLint *values)
645 {
646     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
647     const FunctionsGL *functions = GetFunctionsGL(context);
648     StateManagerGL *stateManager = GetStateManagerGL(context);
649 
650     syncClearBufferState(context, buffer, drawbuffer);
651     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
652 
653     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
654     {
655         functions->clearBufferiv(buffer, drawbuffer, values);
656     }
657     else
658     {
659         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
660         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
661                                             ClearMultiviewGL::ClearCommandType::ClearBufferiv,
662                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
663                                             reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
664     }
665 
666     contextGL->markWorkSubmitted();
667 
668     // Perform cheaper checks first, relying on short-circuiting
669     if (buffer == GL_COLOR && mState.getEnabledDrawBuffers().hasGaps() &&
670         GetFeaturesGL(context).clearsWithGapsNeedFlush.enabled &&
671         IsNonTrivialClearColor(reinterpret_cast<const GLuint *>(values)))
672     {
673         return contextGL->flush(context);
674     }
675 
676     return angle::Result::Continue;
677 }
678 
clearBufferfi(const gl::Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)679 angle::Result FramebufferGL::clearBufferfi(const gl::Context *context,
680                                            GLenum buffer,
681                                            GLint drawbuffer,
682                                            GLfloat depth,
683                                            GLint stencil)
684 {
685     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
686     const FunctionsGL *functions = GetFunctionsGL(context);
687     StateManagerGL *stateManager = GetStateManagerGL(context);
688 
689     syncClearBufferState(context, buffer, drawbuffer);
690     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
691 
692     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
693     {
694         functions->clearBufferfi(buffer, drawbuffer, depth, stencil);
695     }
696     else
697     {
698         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
699         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
700                                             ClearMultiviewGL::ClearCommandType::ClearBufferfi,
701                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
702                                             nullptr, depth, stencil);
703     }
704 
705     contextGL->markWorkSubmitted();
706     return angle::Result::Continue;
707 }
708 
readPixels(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,const gl::PixelPackState & pack,gl::Buffer * packBuffer,void * pixels)709 angle::Result FramebufferGL::readPixels(const gl::Context *context,
710                                         const gl::Rectangle &area,
711                                         GLenum format,
712                                         GLenum type,
713                                         const gl::PixelPackState &pack,
714                                         gl::Buffer *packBuffer,
715                                         void *pixels)
716 {
717     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
718     const FunctionsGL *functions      = GetFunctionsGL(context);
719     StateManagerGL *stateManager      = GetStateManagerGL(context);
720     const angle::FeaturesGL &features = GetFeaturesGL(context);
721     gl::PixelPackState packState      = pack;
722 
723     // Clip read area to framebuffer.
724     const auto *readAttachment = mState.getReadPixelsAttachment(format);
725     const gl::Extents fbSize   = readAttachment->getSize();
726     const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
727     gl::Rectangle clippedArea;
728     if (!ClipRectangle(area, fbRect, &clippedArea))
729     {
730         // nothing to read
731         return angle::Result::Continue;
732     }
733 
734     GLenum attachmentReadFormat =
735         readAttachment->getFormat().info->getReadPixelsFormat(context->getExtensions());
736     nativegl::ReadPixelsFormat readPixelsFormat =
737         nativegl::GetReadPixelsFormat(functions, features, attachmentReadFormat, format, type);
738     GLenum readFormat = readPixelsFormat.format;
739     GLenum readType   = readPixelsFormat.type;
740     if (features.readPixelsUsingImplementationColorReadFormatForNorm16.enabled &&
741         readType == GL_UNSIGNED_SHORT)
742     {
743         ANGLE_CHECK(contextGL, IsValidUnsignedShortReadPixelsFormat(readFormat, context),
744                     "glReadPixels: GL_IMPLEMENTATION_COLOR_READ_FORMAT advertised by the driver is "
745                     "not handled by RGBA16 readPixels workaround.",
746                     GL_INVALID_OPERATION);
747     }
748 
749     GLenum framebufferTarget =
750         stateManager->getHasSeparateFramebufferBindings() ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
751     stateManager->bindFramebuffer(framebufferTarget, mFramebufferID);
752 
753     bool useOverlappingRowsWorkaround = features.packOverlappingRowsSeparatelyPackBuffer.enabled &&
754                                         packBuffer && packState.rowLength != 0 &&
755                                         packState.rowLength < clippedArea.width;
756 
757     GLubyte *outPtr = static_cast<GLubyte *>(pixels);
758     int leftClip    = clippedArea.x - area.x;
759     int topClip     = clippedArea.y - area.y;
760     if (leftClip || topClip)
761     {
762         // Adjust destination to match portion clipped off left and/or top.
763         const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(readFormat, readType);
764 
765         GLuint rowBytes = 0;
766         ANGLE_CHECK_GL_MATH(contextGL,
767                             glFormat.computeRowPitch(readType, area.width, packState.alignment,
768                                                      packState.rowLength, &rowBytes));
769         outPtr += leftClip * glFormat.pixelBytes + topClip * rowBytes;
770     }
771 
772     if (packState.rowLength == 0 && clippedArea.width != area.width)
773     {
774         // No rowLength was specified so it will derive from read width, but clipping changed the
775         // read width.  Use the original width so we fill the user's buffer as they intended.
776         packState.rowLength = area.width;
777     }
778 
779     // We want to use rowLength, but that might not be supported.
780     bool cannotSetDesiredRowLength =
781         packState.rowLength && !GetImplAs<ContextGL>(context)->getNativeExtensions().packSubimageNV;
782 
783     bool usePackSkipWorkaround = features.emulatePackSkipRowsAndPackSkipPixels.enabled &&
784                                  (packState.skipRows != 0 || packState.skipPixels != 0);
785 
786     if (cannotSetDesiredRowLength || useOverlappingRowsWorkaround || usePackSkipWorkaround)
787     {
788         return readPixelsRowByRow(context, clippedArea, format, readFormat, readType, packState,
789                                   outPtr);
790     }
791 
792     bool useLastRowPaddingWorkaround = false;
793     if (features.packLastRowSeparatelyForPaddingInclusion.enabled)
794     {
795         ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
796             contextGL, gl::Extents(clippedArea.width, clippedArea.height, 1), packState, packBuffer,
797             readFormat, readType, false, outPtr, &useLastRowPaddingWorkaround));
798     }
799 
800     return readPixelsAllAtOnce(context, clippedArea, format, readFormat, readType, packState,
801                                outPtr, useLastRowPaddingWorkaround);
802 }
803 
blit(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,GLbitfield mask,GLenum filter)804 angle::Result FramebufferGL::blit(const gl::Context *context,
805                                   const gl::Rectangle &sourceArea,
806                                   const gl::Rectangle &destArea,
807                                   GLbitfield mask,
808                                   GLenum filter)
809 {
810     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
811     const FunctionsGL *functions      = GetFunctionsGL(context);
812     StateManagerGL *stateManager      = GetStateManagerGL(context);
813     const angle::FeaturesGL &features = GetFeaturesGL(context);
814 
815     const Framebuffer *sourceFramebuffer = context->getState().getReadFramebuffer();
816     const Framebuffer *destFramebuffer   = context->getState().getDrawFramebuffer();
817 
818     const FramebufferAttachment *colorReadAttachment = sourceFramebuffer->getReadColorAttachment();
819 
820     GLsizei readAttachmentSamples = 0;
821     if (colorReadAttachment != nullptr)
822     {
823         // Blitting requires that the textures be single sampled. getSamples will return
824         // emulated sample number, but the EXT_multisampled_render_to_texture extension will
825         // take care of resolving the texture, so even if emulated samples > 0, we should still
826         // be able to blit as long as the underlying resource samples is single sampled.
827         readAttachmentSamples = colorReadAttachment->getResourceSamples();
828     }
829 
830     bool needManualColorBlit = false;
831 
832     // TODO(cwallez) when the filter is LINEAR and both source and destination are SRGB, we
833     // could avoid doing a manual blit.
834 
835     // Prior to OpenGL 4.4 BlitFramebuffer (section 18.3.1 of GL 4.3 core profile) reads:
836     //      When values are taken from the read buffer, no linearization is performed, even
837     //      if the format of the buffer is SRGB.
838     // Starting from OpenGL 4.4 (section 18.3.1) it reads:
839     //      When values are taken from the read buffer, if FRAMEBUFFER_SRGB is enabled and the
840     //      value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment
841     //      corresponding to the read buffer is SRGB, the red, green, and blue components are
842     //      converted from the non-linear sRGB color space according [...].
843     {
844         bool sourceSRGB =
845             colorReadAttachment != nullptr && colorReadAttachment->getColorEncoding() == GL_SRGB;
846         needManualColorBlit =
847             needManualColorBlit || (sourceSRGB && functions->isAtMostGL(gl::Version(4, 3)));
848     }
849 
850     // Prior to OpenGL 4.2 BlitFramebuffer (section 4.3.2 of GL 4.1 core profile) reads:
851     //      Blit operations bypass the fragment pipeline. The only fragment operations which
852     //      affect a blit are the pixel ownership test and scissor test.
853     // Starting from OpenGL 4.2 (section 4.3.2) it reads:
854     //      When values are written to the draw buffers, blit operations bypass the fragment
855     //      pipeline. The only fragment operations which affect a blit are the pixel ownership
856     //      test,  the scissor test and sRGB conversion.
857     if (!needManualColorBlit)
858     {
859         bool destSRGB = false;
860         for (size_t i = 0; i < destFramebuffer->getDrawbufferStateCount(); ++i)
861         {
862             const FramebufferAttachment *attachment = destFramebuffer->getDrawBuffer(i);
863             if (attachment && attachment->getColorEncoding() == GL_SRGB)
864             {
865                 destSRGB = true;
866                 break;
867             }
868         }
869 
870         needManualColorBlit =
871             needManualColorBlit || (destSRGB && functions->isAtMostGL(gl::Version(4, 1)));
872     }
873 
874     // If the destination has an emulated alpha channel, we need to blit with a shader with alpha
875     // writes disabled.
876     if (mHasEmulatedAlphaAttachment)
877     {
878         needManualColorBlit = true;
879     }
880 
881     // Enable FRAMEBUFFER_SRGB if needed
882     stateManager->setFramebufferSRGBEnabledForFramebuffer(context, true, this);
883 
884     GLenum blitMask = mask;
885     if (needManualColorBlit && (mask & GL_COLOR_BUFFER_BIT) && readAttachmentSamples <= 1)
886     {
887         BlitGL *blitter = GetBlitGL(context);
888         ANGLE_TRY(blitter->blitColorBufferWithShader(context, sourceFramebuffer, destFramebuffer,
889                                                      sourceArea, destArea, filter,
890                                                      !mHasEmulatedAlphaAttachment));
891         blitMask &= ~GL_COLOR_BUFFER_BIT;
892     }
893 
894     if (blitMask == 0)
895     {
896         return angle::Result::Continue;
897     }
898 
899     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer);
900     stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
901     stateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID);
902 
903     gl::Rectangle finalSourceArea(sourceArea);
904     gl::Rectangle finalDestArea(destArea);
905 
906     if (features.adjustSrcDstRegionForBlitFramebuffer.enabled)
907     {
908         angle::Result result = adjustSrcDstRegion(context, finalSourceArea, finalDestArea,
909                                                   &finalSourceArea, &finalDestArea);
910         if (result != angle::Result::Continue)
911         {
912             return result;
913         }
914     }
915     if (features.clipSrcRegionForBlitFramebuffer.enabled)
916     {
917         angle::Result result = clipSrcRegion(context, finalSourceArea, finalDestArea,
918                                              &finalSourceArea, &finalDestArea);
919         if (result != angle::Result::Continue)
920         {
921             return result;
922         }
923     }
924 
925     functions->blitFramebuffer(finalSourceArea.x, finalSourceArea.y, finalSourceArea.x1(),
926                                finalSourceArea.y1(), finalDestArea.x, finalDestArea.y,
927                                finalDestArea.x1(), finalDestArea.y1(), blitMask, filter);
928 
929     contextGL->markWorkSubmitted();
930     return angle::Result::Continue;
931 }
932 
adjustSrcDstRegion(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,gl::Rectangle * newSourceArea,gl::Rectangle * newDestArea)933 angle::Result FramebufferGL::adjustSrcDstRegion(const gl::Context *context,
934                                                 const gl::Rectangle &sourceArea,
935                                                 const gl::Rectangle &destArea,
936                                                 gl::Rectangle *newSourceArea,
937                                                 gl::Rectangle *newDestArea)
938 {
939     BlitFramebufferBounds bounds = GetBlitFramebufferBounds(context, sourceArea, destArea);
940 
941     if (bounds.destRegion.width == 0 || bounds.sourceRegion.width == 0 ||
942         bounds.destRegion.height == 0 || bounds.sourceRegion.height == 0)
943     {
944         return angle::Result::Stop;
945     }
946     if (!ClipRectangle(bounds.destBounds, bounds.destRegion, nullptr))
947     {
948         return angle::Result::Stop;
949     }
950 
951     if (!bounds.destBounds.encloses(bounds.destRegion))
952     {
953         // destRegion is not within destBounds. We want to adjust it to a
954         // reasonable size. This is done by halving the destRegion until it is at
955         // most twice the size of the framebuffer. We cut it in half instead
956         // of arbitrarily shrinking it to fit so that we don't end up with
957         // non-power-of-two scale factors which could mess up pixel interpolation.
958         // Naively clipping the dst rect and then proportionally sizing the
959         // src rect yields incorrect results.
960 
961         GLuint destXHalvings = 0;
962         GLuint destYHalvings = 0;
963         GLint destOriginX    = bounds.destRegion.x;
964         GLint destOriginY    = bounds.destRegion.y;
965 
966         GLint destClippedWidth = bounds.destRegion.width;
967         while (destClippedWidth > 2 * bounds.destBounds.width)
968         {
969             destClippedWidth = destClippedWidth / 2;
970             destXHalvings++;
971         }
972 
973         GLint destClippedHeight = bounds.destRegion.height;
974         while (destClippedHeight > 2 * bounds.destBounds.height)
975         {
976             destClippedHeight = destClippedHeight / 2;
977             destYHalvings++;
978         }
979 
980         // Before this block, we check that the two rectangles intersect.
981         // Now, compute the location of a new region origin such that we use the
982         // scaled dimensions but the new region has the same intersection as the
983         // original region.
984 
985         GLint left   = bounds.destRegion.x0();
986         GLint right  = bounds.destRegion.x1();
987         GLint top    = bounds.destRegion.y0();
988         GLint bottom = bounds.destRegion.y1();
989 
990         GLint extraXOffset = 0;
991         if (left >= 0 && left < bounds.destBounds.width)
992         {
993             // Left edge is in-bounds
994             destOriginX = bounds.destRegion.x;
995         }
996         else if (right > 0 && right <= bounds.destBounds.width)
997         {
998             // Right edge is in-bounds
999             destOriginX = right - destClippedWidth;
1000         }
1001         else
1002         {
1003             // Region completely spans bounds
1004             extraXOffset = (bounds.destRegion.width - destClippedWidth) / 2;
1005             destOriginX  = bounds.destRegion.x + extraXOffset;
1006         }
1007 
1008         GLint extraYOffset = 0;
1009         if (top >= 0 && top < bounds.destBounds.height)
1010         {
1011             // Top edge is in-bounds
1012             destOriginY = bounds.destRegion.y;
1013         }
1014         else if (bottom > 0 && bottom <= bounds.destBounds.height)
1015         {
1016             // Bottom edge is in-bounds
1017             destOriginY = bottom - destClippedHeight;
1018         }
1019         else
1020         {
1021             // Region completely spans bounds
1022             extraYOffset = (bounds.destRegion.height - destClippedHeight) / 2;
1023             destOriginY  = bounds.destRegion.y + extraYOffset;
1024         }
1025 
1026         // Offsets from the bottom left corner of the original region to
1027         // the bottom left corner of the clipped region.
1028         // This value (after it is scaled) is the respective offset we will apply
1029         // to the src origin.
1030 
1031         CheckedNumeric<GLuint> checkedXOffset(destOriginX - bounds.destRegion.x - extraXOffset / 2);
1032         CheckedNumeric<GLuint> checkedYOffset(destOriginY - bounds.destRegion.y - extraYOffset / 2);
1033 
1034         // if X/Y is reversed, use the top/right out-of-bounds region to compute
1035         // the origin offset instead of the left/bottom out-of-bounds region
1036         if (bounds.xFlipped)
1037         {
1038             checkedXOffset =
1039                 (bounds.destRegion.x1() - (destOriginX + destClippedWidth) + extraXOffset / 2);
1040         }
1041         if (bounds.yFlipped)
1042         {
1043             checkedYOffset =
1044                 (bounds.destRegion.y1() - (destOriginY + destClippedHeight) + extraYOffset / 2);
1045         }
1046 
1047         // These offsets should never overflow
1048         GLuint xOffset, yOffset;
1049         if (!checkedXOffset.AssignIfValid(&xOffset) || !checkedYOffset.AssignIfValid(&yOffset))
1050         {
1051             UNREACHABLE();
1052             return angle::Result::Stop;
1053         }
1054 
1055         bounds.destRegion =
1056             gl::Rectangle(destOriginX, destOriginY, destClippedWidth, destClippedHeight);
1057 
1058         // Adjust the src region by the same factor
1059         bounds.sourceRegion = gl::Rectangle(bounds.sourceRegion.x + (xOffset >> destXHalvings),
1060                                             bounds.sourceRegion.y + (yOffset >> destYHalvings),
1061                                             bounds.sourceRegion.width >> destXHalvings,
1062                                             bounds.sourceRegion.height >> destYHalvings);
1063 
1064         // if the src was scaled to 0, set it to 1 so the src is non-empty
1065         if (bounds.sourceRegion.width == 0)
1066         {
1067             bounds.sourceRegion.width = 1;
1068         }
1069         if (bounds.sourceRegion.height == 0)
1070         {
1071             bounds.sourceRegion.height = 1;
1072         }
1073     }
1074 
1075     if (!bounds.sourceBounds.encloses(bounds.sourceRegion))
1076     {
1077         // sourceRegion is not within sourceBounds. We want to adjust it to a
1078         // reasonable size. This is done by halving the sourceRegion until it is at
1079         // most twice the size of the framebuffer. We cut it in half instead
1080         // of arbitrarily shrinking it to fit so that we don't end up with
1081         // non-power-of-two scale factors which could mess up pixel interpolation.
1082         // Naively clipping the source rect and then proportionally sizing the
1083         // dest rect yields incorrect results.
1084 
1085         GLuint sourceXHalvings = 0;
1086         GLuint sourceYHalvings = 0;
1087         GLint sourceOriginX    = bounds.sourceRegion.x;
1088         GLint sourceOriginY    = bounds.sourceRegion.y;
1089 
1090         GLint sourceClippedWidth = bounds.sourceRegion.width;
1091         while (sourceClippedWidth > 2 * bounds.sourceBounds.width)
1092         {
1093             sourceClippedWidth = sourceClippedWidth / 2;
1094             sourceXHalvings++;
1095         }
1096 
1097         GLint sourceClippedHeight = bounds.sourceRegion.height;
1098         while (sourceClippedHeight > 2 * bounds.sourceBounds.height)
1099         {
1100             sourceClippedHeight = sourceClippedHeight / 2;
1101             sourceYHalvings++;
1102         }
1103 
1104         // Before this block, we check that the two rectangles intersect.
1105         // Now, compute the location of a new region origin such that we use the
1106         // scaled dimensions but the new region has the same intersection as the
1107         // original region.
1108 
1109         GLint left   = bounds.sourceRegion.x0();
1110         GLint right  = bounds.sourceRegion.x1();
1111         GLint top    = bounds.sourceRegion.y0();
1112         GLint bottom = bounds.sourceRegion.y1();
1113 
1114         GLint extraXOffset = 0;
1115         if (left >= 0 && left < bounds.sourceBounds.width)
1116         {
1117             // Left edge is in-bounds
1118             sourceOriginX = bounds.sourceRegion.x;
1119         }
1120         else if (right > 0 && right <= bounds.sourceBounds.width)
1121         {
1122             // Right edge is in-bounds
1123             sourceOriginX = right - sourceClippedWidth;
1124         }
1125         else
1126         {
1127             // Region completely spans bounds
1128             extraXOffset  = (bounds.sourceRegion.width - sourceClippedWidth) / 2;
1129             sourceOriginX = bounds.sourceRegion.x + extraXOffset;
1130         }
1131 
1132         GLint extraYOffset = 0;
1133         if (top >= 0 && top < bounds.sourceBounds.height)
1134         {
1135             // Top edge is in-bounds
1136             sourceOriginY = bounds.sourceRegion.y;
1137         }
1138         else if (bottom > 0 && bottom <= bounds.sourceBounds.height)
1139         {
1140             // Bottom edge is in-bounds
1141             sourceOriginY = bottom - sourceClippedHeight;
1142         }
1143         else
1144         {
1145             // Region completely spans bounds
1146             extraYOffset  = (bounds.sourceRegion.height - sourceClippedHeight) / 2;
1147             sourceOriginY = bounds.sourceRegion.y + extraYOffset;
1148         }
1149 
1150         // Offsets from the bottom left corner of the original region to
1151         // the bottom left corner of the clipped region.
1152         // This value (after it is scaled) is the respective offset we will apply
1153         // to the dest origin.
1154 
1155         CheckedNumeric<GLuint> checkedXOffset(sourceOriginX - bounds.sourceRegion.x -
1156                                               extraXOffset / 2);
1157         CheckedNumeric<GLuint> checkedYOffset(sourceOriginY - bounds.sourceRegion.y -
1158                                               extraYOffset / 2);
1159 
1160         // if X/Y is reversed, use the top/right out-of-bounds region to compute
1161         // the origin offset instead of the left/bottom out-of-bounds region
1162         if (bounds.xFlipped)
1163         {
1164             checkedXOffset = (bounds.sourceRegion.x1() - (sourceOriginX + sourceClippedWidth) +
1165                               extraXOffset / 2);
1166         }
1167         if (bounds.yFlipped)
1168         {
1169             checkedYOffset = (bounds.sourceRegion.y1() - (sourceOriginY + sourceClippedHeight) +
1170                               extraYOffset / 2);
1171         }
1172 
1173         // These offsets should never overflow
1174         GLuint xOffset, yOffset;
1175         if (!checkedXOffset.AssignIfValid(&xOffset) || !checkedYOffset.AssignIfValid(&yOffset))
1176         {
1177             UNREACHABLE();
1178             return angle::Result::Stop;
1179         }
1180 
1181         bounds.sourceRegion =
1182             gl::Rectangle(sourceOriginX, sourceOriginY, sourceClippedWidth, sourceClippedHeight);
1183 
1184         // Adjust the dest region by the same factor
1185         bounds.destRegion = gl::Rectangle(bounds.destRegion.x + (xOffset >> sourceXHalvings),
1186                                           bounds.destRegion.y + (yOffset >> sourceYHalvings),
1187                                           bounds.destRegion.width >> sourceXHalvings,
1188                                           bounds.destRegion.height >> sourceYHalvings);
1189     }
1190     // Set the src and dst endpoints. If they were previously flipped,
1191     // set them as flipped.
1192     *newSourceArea = bounds.sourceRegion.flip(sourceArea.isReversedX(), sourceArea.isReversedY());
1193     *newDestArea   = bounds.destRegion.flip(destArea.isReversedX(), destArea.isReversedY());
1194 
1195     return angle::Result::Continue;
1196 }
1197 
clipSrcRegion(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,gl::Rectangle * newSourceArea,gl::Rectangle * newDestArea)1198 angle::Result FramebufferGL::clipSrcRegion(const gl::Context *context,
1199                                            const gl::Rectangle &sourceArea,
1200                                            const gl::Rectangle &destArea,
1201                                            gl::Rectangle *newSourceArea,
1202                                            gl::Rectangle *newDestArea)
1203 {
1204     BlitFramebufferBounds bounds = GetBlitFramebufferBounds(context, sourceArea, destArea);
1205 
1206     if (bounds.destRegion.width == 0 || bounds.sourceRegion.width == 0 ||
1207         bounds.destRegion.height == 0 || bounds.sourceRegion.height == 0)
1208     {
1209         return angle::Result::Stop;
1210     }
1211     if (!ClipRectangle(bounds.destBounds, bounds.destRegion, nullptr))
1212     {
1213         return angle::Result::Stop;
1214     }
1215 
1216     if (!bounds.sourceBounds.encloses(bounds.sourceRegion))
1217     {
1218         // If pixels lying outside the read framebuffer, adjust src region
1219         // and dst region to appropriate in-bounds regions respectively.
1220         gl::Rectangle realSourceRegion;
1221         if (!ClipRectangle(bounds.sourceRegion, bounds.sourceBounds, &realSourceRegion))
1222         {
1223             return angle::Result::Stop;
1224         }
1225         GLuint xOffset = realSourceRegion.x - bounds.sourceRegion.x;
1226         GLuint yOffset = realSourceRegion.y - bounds.sourceRegion.y;
1227 
1228         // if X/Y is reversed, use the top/right out-of-bounds region for mapping
1229         // to dst region, instead of left/bottom out-of-bounds region for mapping.
1230         if (bounds.xFlipped)
1231         {
1232             xOffset = bounds.sourceRegion.x1() - realSourceRegion.x1();
1233         }
1234         if (bounds.yFlipped)
1235         {
1236             yOffset = bounds.sourceRegion.y1() - realSourceRegion.y1();
1237         }
1238 
1239         GLfloat destMappingWidth = static_cast<GLfloat>(realSourceRegion.width) *
1240                                    bounds.destRegion.width / bounds.sourceRegion.width;
1241         GLfloat destMappingHeight = static_cast<GLfloat>(realSourceRegion.height) *
1242                                     bounds.destRegion.height / bounds.sourceRegion.height;
1243         GLfloat destMappingXOffset =
1244             static_cast<GLfloat>(xOffset) * bounds.destRegion.width / bounds.sourceRegion.width;
1245         GLfloat destMappingYOffset =
1246             static_cast<GLfloat>(yOffset) * bounds.destRegion.height / bounds.sourceRegion.height;
1247 
1248         GLuint destMappingX0 =
1249             static_cast<GLuint>(std::round(bounds.destRegion.x + destMappingXOffset));
1250         GLuint destMappingY0 =
1251             static_cast<GLuint>(std::round(bounds.destRegion.y + destMappingYOffset));
1252 
1253         GLuint destMappingX1 = static_cast<GLuint>(
1254             std::round(bounds.destRegion.x + destMappingXOffset + destMappingWidth));
1255         GLuint destMappingY1 = static_cast<GLuint>(
1256             std::round(bounds.destRegion.y + destMappingYOffset + destMappingHeight));
1257 
1258         bounds.destRegion =
1259             gl::Rectangle(destMappingX0, destMappingY0, destMappingX1 - destMappingX0,
1260                           destMappingY1 - destMappingY0);
1261 
1262         bounds.sourceRegion = realSourceRegion;
1263     }
1264     // Set the src and dst endpoints. If they were previously flipped,
1265     // set them as flipped.
1266     *newSourceArea = bounds.sourceRegion.flip(sourceArea.isReversedX(), sourceArea.isReversedY());
1267     *newDestArea   = bounds.destRegion.flip(destArea.isReversedX(), destArea.isReversedY());
1268 
1269     return angle::Result::Continue;
1270 }
1271 
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const1272 angle::Result FramebufferGL::getSamplePosition(const gl::Context *context,
1273                                                size_t index,
1274                                                GLfloat *xy) const
1275 {
1276     const FunctionsGL *functions = GetFunctionsGL(context);
1277     StateManagerGL *stateManager = GetStateManagerGL(context);
1278 
1279     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
1280     functions->getMultisamplefv(GL_SAMPLE_POSITION, static_cast<GLuint>(index), xy);
1281     return angle::Result::Continue;
1282 }
1283 
shouldSyncStateBeforeCheckStatus() const1284 bool FramebufferGL::shouldSyncStateBeforeCheckStatus() const
1285 {
1286     return true;
1287 }
1288 
checkStatus(const gl::Context * context) const1289 gl::FramebufferStatus FramebufferGL::checkStatus(const gl::Context *context) const
1290 {
1291     const FunctionsGL *functions = GetFunctionsGL(context);
1292     StateManagerGL *stateManager = GetStateManagerGL(context);
1293 
1294     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
1295     GLenum status = functions->checkFramebufferStatus(GL_FRAMEBUFFER);
1296     if (status != GL_FRAMEBUFFER_COMPLETE)
1297     {
1298         WARN() << "GL framebuffer returned incomplete: " << gl::FmtHex(status);
1299         return gl::FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNSUPPORTED,
1300                                                  gl::err::kFramebufferIncompleteDriverUnsupported);
1301     }
1302 
1303     return gl::FramebufferStatus::Complete();
1304 }
1305 
ensureAttachmentsInitialized(const gl::Context * context,const gl::DrawBufferMask & colorAttachments,bool depth,bool stencil)1306 angle::Result FramebufferGL::ensureAttachmentsInitialized(
1307     const gl::Context *context,
1308     const gl::DrawBufferMask &colorAttachments,
1309     bool depth,
1310     bool stencil)
1311 {
1312     if (colorAttachments != getState().getEnabledDrawBuffers())
1313     {
1314         // Fall back to the default implementation when there are gaps in the enabled draw buffers
1315         // to avoid modifying the draw buffer state.
1316         return FramebufferImpl::ensureAttachmentsInitialized(context, colorAttachments, depth,
1317                                                              stencil);
1318     }
1319 
1320     BlitGL *blitter = GetBlitGL(context);
1321     return blitter->clearFramebuffer(context, colorAttachments, depth, stencil, this);
1322 }
1323 
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)1324 angle::Result FramebufferGL::syncState(const gl::Context *context,
1325                                        GLenum binding,
1326                                        const gl::Framebuffer::DirtyBits &dirtyBits,
1327                                        gl::Command command)
1328 {
1329     // Don't need to sync state for the default FBO.
1330     if (isDefault())
1331     {
1332         return angle::Result::Continue;
1333     }
1334 
1335     const FunctionsGL *functions = GetFunctionsGL(context);
1336     StateManagerGL *stateManager = GetStateManagerGL(context);
1337 
1338     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
1339 
1340     // A pointer to one of the attachments for which the texture or the render buffer is not zero.
1341     const FramebufferAttachment *attachment = nullptr;
1342 
1343     for (auto dirtyBit : dirtyBits)
1344     {
1345         switch (dirtyBit)
1346         {
1347             case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
1348             {
1349                 const FramebufferAttachment *newAttachment = mState.getDepthAttachment();
1350                 BindFramebufferAttachment(functions, GL_DEPTH_ATTACHMENT, newAttachment,
1351                                           GetFeaturesGL(context));
1352                 if (newAttachment)
1353                 {
1354                     attachment = newAttachment;
1355                 }
1356                 break;
1357             }
1358             case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
1359             {
1360                 const FramebufferAttachment *newAttachment = mState.getStencilAttachment();
1361                 BindFramebufferAttachment(functions, GL_STENCIL_ATTACHMENT, newAttachment,
1362                                           GetFeaturesGL(context));
1363                 if (newAttachment)
1364                 {
1365                     attachment = newAttachment;
1366                 }
1367                 break;
1368             }
1369             case Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
1370             {
1371                 const auto &drawBuffers = mState.getDrawBufferStates();
1372                 functions->drawBuffers(static_cast<GLsizei>(drawBuffers.size()),
1373                                        drawBuffers.data());
1374                 mAppliedEnabledDrawBuffers = mState.getEnabledDrawBuffers();
1375                 break;
1376             }
1377             case Framebuffer::DIRTY_BIT_READ_BUFFER:
1378                 functions->readBuffer(mState.getReadBufferState());
1379                 break;
1380             case Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
1381                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
1382                                                  mState.getDefaultWidth());
1383                 break;
1384             case Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
1385                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
1386                                                  mState.getDefaultHeight());
1387                 break;
1388             case Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
1389                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES,
1390                                                  mState.getDefaultSamples());
1391                 break;
1392             case Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
1393                 functions->framebufferParameteri(
1394                     GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS,
1395                     gl::ConvertToGLBoolean(mState.getDefaultFixedSampleLocations()));
1396                 break;
1397             case Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
1398                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT,
1399                                                  mState.getDefaultLayers());
1400                 break;
1401             case Framebuffer::DIRTY_BIT_FLIP_Y:
1402                 ASSERT(functions->framebufferParameteri || functions->framebufferParameteriMESA);
1403                 if (functions->framebufferParameteri)
1404                 {
1405                     functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA,
1406                                                      gl::ConvertToGLBoolean(mState.getFlipY()));
1407                 }
1408                 else
1409                 {
1410                     functions->framebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA,
1411                                                          gl::ConvertToGLBoolean(mState.getFlipY()));
1412                 }
1413                 break;
1414             default:
1415             {
1416                 static_assert(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
1417                 if (dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
1418                 {
1419                     size_t index =
1420                         static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
1421                     const FramebufferAttachment *newAttachment = mState.getColorAttachment(index);
1422                     BindFramebufferAttachment(functions,
1423                                               static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
1424                                               newAttachment, GetFeaturesGL(context));
1425                     if (newAttachment)
1426                     {
1427                         attachment = newAttachment;
1428                     }
1429 
1430                     // Hiding an alpha channel is only supported when it's the first attachment
1431                     // currently. Assert that these emulated textures are not bound to a framebuffer
1432                     // using MRT.
1433                     if (index == 0)
1434                     {
1435                         mHasEmulatedAlphaAttachment =
1436                             IsEmulatedAlphaChannelTextureAttachment(attachment);
1437                     }
1438                     ASSERT(index == 0 || !IsEmulatedAlphaChannelTextureAttachment(attachment));
1439                 }
1440                 break;
1441             }
1442         }
1443     }
1444 
1445     if (attachment && mState.id() == context->getState().getDrawFramebuffer()->id())
1446     {
1447         stateManager->updateMultiviewBaseViewLayerIndexUniform(
1448             context->getState().getProgramExecutable(), getState());
1449     }
1450 
1451     return angle::Result::Continue;
1452 }
1453 
updateDefaultFramebufferID(GLuint framebufferID)1454 void FramebufferGL::updateDefaultFramebufferID(GLuint framebufferID)
1455 {
1456     // We only update framebufferID for a default frambuffer, and the framebufferID is created
1457     // externally. ANGLE doesn't owne it.
1458     ASSERT(isDefault());
1459     mFramebufferID = framebufferID;
1460 }
1461 
hasEmulatedAlphaChannelTextureAttachment() const1462 bool FramebufferGL::hasEmulatedAlphaChannelTextureAttachment() const
1463 {
1464     return mHasEmulatedAlphaAttachment;
1465 }
1466 
syncClearState(const gl::Context * context,GLbitfield mask)1467 void FramebufferGL::syncClearState(const gl::Context *context, GLbitfield mask)
1468 {
1469     StateManagerGL *stateManager      = GetStateManagerGL(context);
1470     const angle::FeaturesGL &features = GetFeaturesGL(context);
1471 
1472     // Clip origin must not affect scissor box but some drivers flip it for clear ops.
1473     if (context->getState().isScissorTestEnabled())
1474     {
1475         stateManager->setClipControl(ClipOrigin::LowerLeft, ClipDepthMode::NegativeOneToOne);
1476     }
1477 
1478     if (features.doesSRGBClearsOnLinearFramebufferAttachments.enabled &&
1479         (mask & GL_COLOR_BUFFER_BIT) != 0 && !isDefault())
1480     {
1481         bool hasSRGBAttachment = false;
1482         for (const auto &attachment : mState.getColorAttachments())
1483         {
1484             if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB)
1485             {
1486                 hasSRGBAttachment = true;
1487                 break;
1488             }
1489         }
1490 
1491         stateManager->setFramebufferSRGBEnabled(context, hasSRGBAttachment);
1492     }
1493     else
1494     {
1495         stateManager->setFramebufferSRGBEnabled(context, !isDefault());
1496     }
1497 }
1498 
syncClearBufferState(const gl::Context * context,GLenum buffer,GLint drawBuffer)1499 void FramebufferGL::syncClearBufferState(const gl::Context *context,
1500                                          GLenum buffer,
1501                                          GLint drawBuffer)
1502 {
1503     StateManagerGL *stateManager      = GetStateManagerGL(context);
1504     const angle::FeaturesGL &features = GetFeaturesGL(context);
1505 
1506     // Clip origin must not affect scissor box but some drivers flip it for clear ops.
1507     if (context->getState().isScissorTestEnabled())
1508     {
1509         stateManager->setClipControl(ClipOrigin::LowerLeft, ClipDepthMode::NegativeOneToOne);
1510     }
1511 
1512     if (features.doesSRGBClearsOnLinearFramebufferAttachments.enabled && buffer == GL_COLOR &&
1513         !isDefault())
1514     {
1515         // If doing a clear on a color buffer, set SRGB blend enabled only if the color buffer
1516         // is an SRGB format.
1517         const auto &drawbufferState  = mState.getDrawBufferStates();
1518         const auto &colorAttachments = mState.getColorAttachments();
1519 
1520         const FramebufferAttachment *attachment = nullptr;
1521         if (drawbufferState[drawBuffer] >= GL_COLOR_ATTACHMENT0 &&
1522             drawbufferState[drawBuffer] < GL_COLOR_ATTACHMENT0 + colorAttachments.size())
1523         {
1524             size_t attachmentIdx =
1525                 static_cast<size_t>(drawbufferState[drawBuffer] - GL_COLOR_ATTACHMENT0);
1526             attachment = &colorAttachments[attachmentIdx];
1527         }
1528 
1529         if (attachment != nullptr)
1530         {
1531             stateManager->setFramebufferSRGBEnabled(context,
1532                                                     attachment->getColorEncoding() == GL_SRGB);
1533         }
1534     }
1535     else
1536     {
1537         stateManager->setFramebufferSRGBEnabled(context, !isDefault());
1538     }
1539 }
1540 
modifyInvalidateAttachmentsForEmulatedDefaultFBO(size_t count,const GLenum * attachments,std::vector<GLenum> * modifiedAttachments) const1541 bool FramebufferGL::modifyInvalidateAttachmentsForEmulatedDefaultFBO(
1542     size_t count,
1543     const GLenum *attachments,
1544     std::vector<GLenum> *modifiedAttachments) const
1545 {
1546     bool needsModification = isDefault() && mFramebufferID != 0;
1547     if (!needsModification)
1548     {
1549         return false;
1550     }
1551 
1552     modifiedAttachments->resize(count);
1553     for (size_t i = 0; i < count; i++)
1554     {
1555         switch (attachments[i])
1556         {
1557             case GL_COLOR:
1558                 (*modifiedAttachments)[i] = GL_COLOR_ATTACHMENT0;
1559                 break;
1560 
1561             case GL_DEPTH:
1562                 (*modifiedAttachments)[i] = GL_DEPTH_ATTACHMENT;
1563                 break;
1564 
1565             case GL_STENCIL:
1566                 (*modifiedAttachments)[i] = GL_STENCIL_ATTACHMENT;
1567                 break;
1568 
1569             default:
1570                 UNREACHABLE();
1571                 break;
1572         }
1573     }
1574 
1575     return true;
1576 }
1577 
readPixelsRowByRow(const gl::Context * context,const gl::Rectangle & area,GLenum originalReadFormat,GLenum format,GLenum type,const gl::PixelPackState & pack,GLubyte * pixels) const1578 angle::Result FramebufferGL::readPixelsRowByRow(const gl::Context *context,
1579                                                 const gl::Rectangle &area,
1580                                                 GLenum originalReadFormat,
1581                                                 GLenum format,
1582                                                 GLenum type,
1583                                                 const gl::PixelPackState &pack,
1584                                                 GLubyte *pixels) const
1585 {
1586     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1587     const FunctionsGL *functions      = GetFunctionsGL(context);
1588     StateManagerGL *stateManager      = GetStateManagerGL(context);
1589     GLubyte *originalReadFormatPixels = pixels;
1590 
1591     const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
1592 
1593     GLuint rowBytes = 0;
1594     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, pack.alignment,
1595                                                             pack.rowLength, &rowBytes));
1596     GLuint skipBytes = 0;
1597     ANGLE_CHECK_GL_MATH(contextGL,
1598                         glFormat.computeSkipBytes(type, rowBytes, 0, pack, false, &skipBytes));
1599 
1600     ScopedEXTTextureNorm16ReadbackWorkaround workaround;
1601     angle::Result result =
1602         workaround.Initialize(context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1603                               glFormat.computePixelBytes(type), pixels);
1604     if (result != angle::Result::Continue)
1605     {
1606         return result;
1607     }
1608 
1609     gl::PixelPackState directPack;
1610     directPack.alignment = 1;
1611     ANGLE_TRY(stateManager->setPixelPackState(context, directPack));
1612 
1613     GLubyte *readbackPixels = workaround.Pixels();
1614     readbackPixels += skipBytes;
1615     for (GLint y = area.y; y < area.y + area.height; ++y)
1616     {
1617         ANGLE_GL_TRY(context,
1618                      functions->readPixels(area.x, y, area.width, 1, format, type, readbackPixels));
1619         readbackPixels += rowBytes;
1620     }
1621 
1622     if (workaround.IsEnabled())
1623     {
1624         return RearrangeEXTTextureNorm16Pixels(
1625             context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1626             glFormat.computePixelBytes(type), pack, originalReadFormatPixels, workaround.Pixels());
1627     }
1628 
1629     return angle::Result::Continue;
1630 }
1631 
readPixelsAllAtOnce(const gl::Context * context,const gl::Rectangle & area,GLenum originalReadFormat,GLenum format,GLenum type,const gl::PixelPackState & pack,GLubyte * pixels,bool readLastRowSeparately) const1632 angle::Result FramebufferGL::readPixelsAllAtOnce(const gl::Context *context,
1633                                                  const gl::Rectangle &area,
1634                                                  GLenum originalReadFormat,
1635                                                  GLenum format,
1636                                                  GLenum type,
1637                                                  const gl::PixelPackState &pack,
1638                                                  GLubyte *pixels,
1639                                                  bool readLastRowSeparately) const
1640 {
1641     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1642     const FunctionsGL *functions      = GetFunctionsGL(context);
1643     StateManagerGL *stateManager      = GetStateManagerGL(context);
1644     GLubyte *originalReadFormatPixels = pixels;
1645 
1646     const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
1647 
1648     GLuint rowBytes = 0;
1649     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, pack.alignment,
1650                                                             pack.rowLength, &rowBytes));
1651     GLuint skipBytes = 0;
1652     ANGLE_CHECK_GL_MATH(contextGL,
1653                         glFormat.computeSkipBytes(type, rowBytes, 0, pack, false, &skipBytes));
1654 
1655     ScopedEXTTextureNorm16ReadbackWorkaround workaround;
1656     angle::Result result =
1657         workaround.Initialize(context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1658                               glFormat.computePixelBytes(type), pixels);
1659     if (result != angle::Result::Continue)
1660     {
1661         return result;
1662     }
1663 
1664     GLint height = area.height - readLastRowSeparately;
1665     if (height > 0)
1666     {
1667         ANGLE_TRY(stateManager->setPixelPackState(context, pack));
1668         ANGLE_GL_TRY(context, functions->readPixels(area.x, area.y, area.width, height, format,
1669                                                     type, workaround.Pixels()));
1670     }
1671 
1672     if (readLastRowSeparately)
1673     {
1674         gl::PixelPackState directPack;
1675         directPack.alignment = 1;
1676         ANGLE_TRY(stateManager->setPixelPackState(context, directPack));
1677 
1678         GLubyte *readbackPixels = workaround.Pixels();
1679         readbackPixels += skipBytes + (area.height - 1) * rowBytes;
1680         ANGLE_GL_TRY(context, functions->readPixels(area.x, area.y + area.height - 1, area.width, 1,
1681                                                     format, type, readbackPixels));
1682     }
1683 
1684     if (workaround.IsEnabled())
1685     {
1686         return RearrangeEXTTextureNorm16Pixels(
1687             context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1688             glFormat.computePixelBytes(type), pack, originalReadFormatPixels, workaround.Pixels());
1689     }
1690 
1691     return angle::Result::Continue;
1692 }
1693 }  // namespace rx
1694