• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }  // namespace
417 
FramebufferGL(const gl::FramebufferState & data,GLuint id,bool emulatedAlpha)418 FramebufferGL::FramebufferGL(const gl::FramebufferState &data, GLuint id, bool emulatedAlpha)
419     : FramebufferImpl(data),
420       mFramebufferID(id),
421       mHasEmulatedAlphaAttachment(emulatedAlpha),
422       mAppliedEnabledDrawBuffers(1)
423 {
424     ASSERT((isDefault() && id == 0) || !isDefault());
425 }
426 
~FramebufferGL()427 FramebufferGL::~FramebufferGL()
428 {
429     ASSERT(mFramebufferID == 0);
430 }
431 
destroy(const gl::Context * context)432 void FramebufferGL::destroy(const gl::Context *context)
433 {
434     if (mFramebufferID)
435     {
436         ASSERT(!isDefault());
437         StateManagerGL *stateManager = GetStateManagerGL(context);
438         stateManager->deleteFramebuffer(mFramebufferID);
439         mFramebufferID = 0;
440     }
441 }
442 
discard(const gl::Context * context,size_t count,const GLenum * attachments)443 angle::Result FramebufferGL::discard(const gl::Context *context,
444                                      size_t count,
445                                      const GLenum *attachments)
446 {
447     // glInvalidateFramebuffer accepts the same enums as glDiscardFramebufferEXT
448     return invalidate(context, count, attachments);
449 }
450 
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)451 angle::Result FramebufferGL::invalidate(const gl::Context *context,
452                                         size_t count,
453                                         const GLenum *attachments)
454 {
455     const GLenum *finalAttachmentsPtr = attachments;
456 
457     std::vector<GLenum> modifiedAttachments;
458     if (modifyInvalidateAttachmentsForEmulatedDefaultFBO(count, attachments, &modifiedAttachments))
459     {
460         finalAttachmentsPtr = modifiedAttachments.data();
461     }
462 
463     const FunctionsGL *functions = GetFunctionsGL(context);
464     StateManagerGL *stateManager = GetStateManagerGL(context);
465 
466     // Since this function is just a hint, only call a native function if it exists.
467     if (functions->invalidateFramebuffer)
468     {
469         stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
470         functions->invalidateFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
471                                          finalAttachmentsPtr);
472     }
473     else if (functions->discardFramebufferEXT)
474     {
475         stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
476         functions->discardFramebufferEXT(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
477                                          finalAttachmentsPtr);
478     }
479 
480     return angle::Result::Continue;
481 }
482 
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)483 angle::Result FramebufferGL::invalidateSub(const gl::Context *context,
484                                            size_t count,
485                                            const GLenum *attachments,
486                                            const gl::Rectangle &area)
487 {
488 
489     const GLenum *finalAttachmentsPtr = attachments;
490 
491     std::vector<GLenum> modifiedAttachments;
492     if (modifyInvalidateAttachmentsForEmulatedDefaultFBO(count, attachments, &modifiedAttachments))
493     {
494         finalAttachmentsPtr = modifiedAttachments.data();
495     }
496 
497     const FunctionsGL *functions = GetFunctionsGL(context);
498     StateManagerGL *stateManager = GetStateManagerGL(context);
499 
500     // Since this function is just a hint and not available until OpenGL 4.3, only call it if it is
501     // available.
502     if (functions->invalidateSubFramebuffer)
503     {
504         stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
505         functions->invalidateSubFramebuffer(GL_FRAMEBUFFER, static_cast<GLsizei>(count),
506                                             finalAttachmentsPtr, area.x, area.y, area.width,
507                                             area.height);
508     }
509 
510     return angle::Result::Continue;
511 }
512 
clear(const gl::Context * context,GLbitfield mask)513 angle::Result FramebufferGL::clear(const gl::Context *context, GLbitfield mask)
514 {
515     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
516     const FunctionsGL *functions = GetFunctionsGL(context);
517     StateManagerGL *stateManager = GetStateManagerGL(context);
518 
519     syncClearState(context, mask);
520     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
521 
522     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
523     {
524         functions->clear(mask);
525     }
526     else
527     {
528         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
529         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
530                                             ClearMultiviewGL::ClearCommandType::Clear, mask,
531                                             GL_NONE, 0, nullptr, 0.0f, 0);
532     }
533 
534     contextGL->markWorkSubmitted();
535     return angle::Result::Continue;
536 }
537 
clearBufferfv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)538 angle::Result FramebufferGL::clearBufferfv(const gl::Context *context,
539                                            GLenum buffer,
540                                            GLint drawbuffer,
541                                            const GLfloat *values)
542 {
543     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
544     const FunctionsGL *functions = GetFunctionsGL(context);
545     StateManagerGL *stateManager = GetStateManagerGL(context);
546 
547     syncClearBufferState(context, buffer, drawbuffer);
548     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
549 
550     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
551     {
552         functions->clearBufferfv(buffer, drawbuffer, values);
553     }
554     else
555     {
556         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
557         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
558                                             ClearMultiviewGL::ClearCommandType::ClearBufferfv,
559                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
560                                             reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
561     }
562 
563     contextGL->markWorkSubmitted();
564     return angle::Result::Continue;
565 }
566 
clearBufferuiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)567 angle::Result FramebufferGL::clearBufferuiv(const gl::Context *context,
568                                             GLenum buffer,
569                                             GLint drawbuffer,
570                                             const GLuint *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->clearBufferuiv(buffer, drawbuffer, values);
582     }
583     else
584     {
585         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
586         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
587                                             ClearMultiviewGL::ClearCommandType::ClearBufferuiv,
588                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
589                                             reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
590     }
591 
592     contextGL->markWorkSubmitted();
593     return angle::Result::Continue;
594 }
595 
clearBufferiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)596 angle::Result FramebufferGL::clearBufferiv(const gl::Context *context,
597                                            GLenum buffer,
598                                            GLint drawbuffer,
599                                            const GLint *values)
600 {
601     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
602     const FunctionsGL *functions = GetFunctionsGL(context);
603     StateManagerGL *stateManager = GetStateManagerGL(context);
604 
605     syncClearBufferState(context, buffer, drawbuffer);
606     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
607 
608     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
609     {
610         functions->clearBufferiv(buffer, drawbuffer, values);
611     }
612     else
613     {
614         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
615         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
616                                             ClearMultiviewGL::ClearCommandType::ClearBufferiv,
617                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
618                                             reinterpret_cast<const uint8_t *>(values), 0.0f, 0);
619     }
620 
621     contextGL->markWorkSubmitted();
622     return angle::Result::Continue;
623 }
624 
clearBufferfi(const gl::Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)625 angle::Result FramebufferGL::clearBufferfi(const gl::Context *context,
626                                            GLenum buffer,
627                                            GLint drawbuffer,
628                                            GLfloat depth,
629                                            GLint stencil)
630 {
631     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
632     const FunctionsGL *functions = GetFunctionsGL(context);
633     StateManagerGL *stateManager = GetStateManagerGL(context);
634 
635     syncClearBufferState(context, buffer, drawbuffer);
636     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
637 
638     if (!RequiresMultiviewClear(mState, context->getState().isScissorTestEnabled()))
639     {
640         functions->clearBufferfi(buffer, drawbuffer, depth, stencil);
641     }
642     else
643     {
644         ClearMultiviewGL *multiviewClearer = GetMultiviewClearer(context);
645         multiviewClearer->clearMultiviewFBO(mState, context->getState().getScissor(),
646                                             ClearMultiviewGL::ClearCommandType::ClearBufferfi,
647                                             static_cast<GLbitfield>(0u), buffer, drawbuffer,
648                                             nullptr, depth, stencil);
649     }
650 
651     contextGL->markWorkSubmitted();
652     return angle::Result::Continue;
653 }
654 
readPixels(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,const gl::PixelPackState & pack,gl::Buffer * packBuffer,void * pixels)655 angle::Result FramebufferGL::readPixels(const gl::Context *context,
656                                         const gl::Rectangle &area,
657                                         GLenum format,
658                                         GLenum type,
659                                         const gl::PixelPackState &pack,
660                                         gl::Buffer *packBuffer,
661                                         void *pixels)
662 {
663     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
664     const FunctionsGL *functions      = GetFunctionsGL(context);
665     StateManagerGL *stateManager      = GetStateManagerGL(context);
666     const angle::FeaturesGL &features = GetFeaturesGL(context);
667     gl::PixelPackState packState      = pack;
668 
669     // Clip read area to framebuffer.
670     const auto *readAttachment = mState.getReadPixelsAttachment(format);
671     const gl::Extents fbSize   = readAttachment->getSize();
672     const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
673     gl::Rectangle clippedArea;
674     if (!ClipRectangle(area, fbRect, &clippedArea))
675     {
676         // nothing to read
677         return angle::Result::Continue;
678     }
679 
680     GLenum attachmentReadFormat =
681         readAttachment->getFormat().info->getReadPixelsFormat(context->getExtensions());
682     nativegl::ReadPixelsFormat readPixelsFormat =
683         nativegl::GetReadPixelsFormat(functions, features, attachmentReadFormat, format, type);
684     GLenum readFormat = readPixelsFormat.format;
685     GLenum readType   = readPixelsFormat.type;
686     if (features.readPixelsUsingImplementationColorReadFormatForNorm16.enabled &&
687         readType == GL_UNSIGNED_SHORT)
688     {
689         ANGLE_CHECK(contextGL, IsValidUnsignedShortReadPixelsFormat(readFormat, context),
690                     "glReadPixels: GL_IMPLEMENTATION_COLOR_READ_FORMAT advertised by the driver is "
691                     "not handled by RGBA16 readPixels workaround.",
692                     GL_INVALID_OPERATION);
693     }
694 
695     GLenum framebufferTarget =
696         stateManager->getHasSeparateFramebufferBindings() ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
697     stateManager->bindFramebuffer(framebufferTarget, mFramebufferID);
698 
699     bool useOverlappingRowsWorkaround = features.packOverlappingRowsSeparatelyPackBuffer.enabled &&
700                                         packBuffer && packState.rowLength != 0 &&
701                                         packState.rowLength < clippedArea.width;
702 
703     GLubyte *outPtr = static_cast<GLubyte *>(pixels);
704     int leftClip    = clippedArea.x - area.x;
705     int topClip     = clippedArea.y - area.y;
706     if (leftClip || topClip)
707     {
708         // Adjust destination to match portion clipped off left and/or top.
709         const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(readFormat, readType);
710 
711         GLuint rowBytes = 0;
712         ANGLE_CHECK_GL_MATH(contextGL,
713                             glFormat.computeRowPitch(readType, area.width, packState.alignment,
714                                                      packState.rowLength, &rowBytes));
715         outPtr += leftClip * glFormat.pixelBytes + topClip * rowBytes;
716     }
717 
718     if (packState.rowLength == 0 && clippedArea.width != area.width)
719     {
720         // No rowLength was specified so it will derive from read width, but clipping changed the
721         // read width.  Use the original width so we fill the user's buffer as they intended.
722         packState.rowLength = area.width;
723     }
724 
725     // We want to use rowLength, but that might not be supported.
726     bool cannotSetDesiredRowLength =
727         packState.rowLength && !GetImplAs<ContextGL>(context)->getNativeExtensions().packSubimageNV;
728 
729     bool usePackSkipWorkaround = features.emulatePackSkipRowsAndPackSkipPixels.enabled &&
730                                  (packState.skipRows != 0 || packState.skipPixels != 0);
731 
732     if (cannotSetDesiredRowLength || useOverlappingRowsWorkaround || usePackSkipWorkaround)
733     {
734         return readPixelsRowByRow(context, clippedArea, format, readFormat, readType, packState,
735                                   outPtr);
736     }
737 
738     bool useLastRowPaddingWorkaround = false;
739     if (features.packLastRowSeparatelyForPaddingInclusion.enabled)
740     {
741         ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
742             contextGL, gl::Extents(clippedArea.width, clippedArea.height, 1), packState, packBuffer,
743             readFormat, readType, false, outPtr, &useLastRowPaddingWorkaround));
744     }
745 
746     return readPixelsAllAtOnce(context, clippedArea, format, readFormat, readType, packState,
747                                outPtr, useLastRowPaddingWorkaround);
748 }
749 
blit(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,GLbitfield mask,GLenum filter)750 angle::Result FramebufferGL::blit(const gl::Context *context,
751                                   const gl::Rectangle &sourceArea,
752                                   const gl::Rectangle &destArea,
753                                   GLbitfield mask,
754                                   GLenum filter)
755 {
756     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
757     const FunctionsGL *functions      = GetFunctionsGL(context);
758     StateManagerGL *stateManager      = GetStateManagerGL(context);
759     const angle::FeaturesGL &features = GetFeaturesGL(context);
760 
761     const Framebuffer *sourceFramebuffer = context->getState().getReadFramebuffer();
762     const Framebuffer *destFramebuffer   = context->getState().getDrawFramebuffer();
763 
764     const FramebufferAttachment *colorReadAttachment = sourceFramebuffer->getReadColorAttachment();
765 
766     GLsizei readAttachmentSamples = 0;
767     if (colorReadAttachment != nullptr)
768     {
769         // Blitting requires that the textures be single sampled. getSamples will return
770         // emulated sample number, but the EXT_multisampled_render_to_texture extension will
771         // take care of resolving the texture, so even if emulated samples > 0, we should still
772         // be able to blit as long as the underlying resource samples is single sampled.
773         readAttachmentSamples = colorReadAttachment->getResourceSamples();
774     }
775 
776     bool needManualColorBlit = false;
777 
778     // TODO(cwallez) when the filter is LINEAR and both source and destination are SRGB, we
779     // could avoid doing a manual blit.
780 
781     // Prior to OpenGL 4.4 BlitFramebuffer (section 18.3.1 of GL 4.3 core profile) reads:
782     //      When values are taken from the read buffer, no linearization is performed, even
783     //      if the format of the buffer is SRGB.
784     // Starting from OpenGL 4.4 (section 18.3.1) it reads:
785     //      When values are taken from the read buffer, if FRAMEBUFFER_SRGB is enabled and the
786     //      value of FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING for the framebuffer attachment
787     //      corresponding to the read buffer is SRGB, the red, green, and blue components are
788     //      converted from the non-linear sRGB color space according [...].
789     {
790         bool sourceSRGB =
791             colorReadAttachment != nullptr && colorReadAttachment->getColorEncoding() == GL_SRGB;
792         needManualColorBlit =
793             needManualColorBlit || (sourceSRGB && functions->isAtMostGL(gl::Version(4, 3)));
794     }
795 
796     // Prior to OpenGL 4.2 BlitFramebuffer (section 4.3.2 of GL 4.1 core profile) reads:
797     //      Blit operations bypass the fragment pipeline. The only fragment operations which
798     //      affect a blit are the pixel ownership test and scissor test.
799     // Starting from OpenGL 4.2 (section 4.3.2) it reads:
800     //      When values are written to the draw buffers, blit operations bypass the fragment
801     //      pipeline. The only fragment operations which affect a blit are the pixel ownership
802     //      test,  the scissor test and sRGB conversion.
803     if (!needManualColorBlit)
804     {
805         bool destSRGB = false;
806         for (size_t i = 0; i < destFramebuffer->getDrawbufferStateCount(); ++i)
807         {
808             const FramebufferAttachment *attachment = destFramebuffer->getDrawBuffer(i);
809             if (attachment && attachment->getColorEncoding() == GL_SRGB)
810             {
811                 destSRGB = true;
812                 break;
813             }
814         }
815 
816         needManualColorBlit =
817             needManualColorBlit || (destSRGB && functions->isAtMostGL(gl::Version(4, 1)));
818     }
819 
820     // If the destination has an emulated alpha channel, we need to blit with a shader with alpha
821     // writes disabled.
822     if (mHasEmulatedAlphaAttachment)
823     {
824         needManualColorBlit = true;
825     }
826 
827     // Enable FRAMEBUFFER_SRGB if needed
828     stateManager->setFramebufferSRGBEnabledForFramebuffer(context, true, this);
829 
830     GLenum blitMask = mask;
831     if (needManualColorBlit && (mask & GL_COLOR_BUFFER_BIT) && readAttachmentSamples <= 1)
832     {
833         BlitGL *blitter = GetBlitGL(context);
834         ANGLE_TRY(blitter->blitColorBufferWithShader(context, sourceFramebuffer, destFramebuffer,
835                                                      sourceArea, destArea, filter,
836                                                      !mHasEmulatedAlphaAttachment));
837         blitMask &= ~GL_COLOR_BUFFER_BIT;
838     }
839 
840     if (blitMask == 0)
841     {
842         return angle::Result::Continue;
843     }
844 
845     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(sourceFramebuffer);
846     stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
847     stateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebufferID);
848 
849     gl::Rectangle finalSourceArea(sourceArea);
850     gl::Rectangle finalDestArea(destArea);
851 
852     if (features.adjustSrcDstRegionForBlitFramebuffer.enabled)
853     {
854         angle::Result result = adjustSrcDstRegion(context, finalSourceArea, finalDestArea,
855                                                   &finalSourceArea, &finalDestArea);
856         if (result != angle::Result::Continue)
857         {
858             return result;
859         }
860     }
861     if (features.clipSrcRegionForBlitFramebuffer.enabled)
862     {
863         angle::Result result = clipSrcRegion(context, finalSourceArea, finalDestArea,
864                                              &finalSourceArea, &finalDestArea);
865         if (result != angle::Result::Continue)
866         {
867             return result;
868         }
869     }
870 
871     functions->blitFramebuffer(finalSourceArea.x, finalSourceArea.y, finalSourceArea.x1(),
872                                finalSourceArea.y1(), finalDestArea.x, finalDestArea.y,
873                                finalDestArea.x1(), finalDestArea.y1(), blitMask, filter);
874 
875     contextGL->markWorkSubmitted();
876     return angle::Result::Continue;
877 }
878 
adjustSrcDstRegion(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,gl::Rectangle * newSourceArea,gl::Rectangle * newDestArea)879 angle::Result FramebufferGL::adjustSrcDstRegion(const gl::Context *context,
880                                                 const gl::Rectangle &sourceArea,
881                                                 const gl::Rectangle &destArea,
882                                                 gl::Rectangle *newSourceArea,
883                                                 gl::Rectangle *newDestArea)
884 {
885     BlitFramebufferBounds bounds = GetBlitFramebufferBounds(context, sourceArea, destArea);
886 
887     if (bounds.destRegion.width == 0 || bounds.sourceRegion.width == 0 ||
888         bounds.destRegion.height == 0 || bounds.sourceRegion.height == 0)
889     {
890         return angle::Result::Stop;
891     }
892     if (!ClipRectangle(bounds.destBounds, bounds.destRegion, nullptr))
893     {
894         return angle::Result::Stop;
895     }
896 
897     if (!bounds.destBounds.encloses(bounds.destRegion))
898     {
899         // destRegion is not within destBounds. We want to adjust it to a
900         // reasonable size. This is done by halving the destRegion until it is at
901         // most twice the size of the framebuffer. We cut it in half instead
902         // of arbitrarily shrinking it to fit so that we don't end up with
903         // non-power-of-two scale factors which could mess up pixel interpolation.
904         // Naively clipping the dst rect and then proportionally sizing the
905         // src rect yields incorrect results.
906 
907         GLuint destXHalvings = 0;
908         GLuint destYHalvings = 0;
909         GLint destOriginX    = bounds.destRegion.x;
910         GLint destOriginY    = bounds.destRegion.y;
911 
912         GLint destClippedWidth = bounds.destRegion.width;
913         while (destClippedWidth > 2 * bounds.destBounds.width)
914         {
915             destClippedWidth = destClippedWidth / 2;
916             destXHalvings++;
917         }
918 
919         GLint destClippedHeight = bounds.destRegion.height;
920         while (destClippedHeight > 2 * bounds.destBounds.height)
921         {
922             destClippedHeight = destClippedHeight / 2;
923             destYHalvings++;
924         }
925 
926         // Before this block, we check that the two rectangles intersect.
927         // Now, compute the location of a new region origin such that we use the
928         // scaled dimensions but the new region has the same intersection as the
929         // original region.
930 
931         GLint left   = bounds.destRegion.x0();
932         GLint right  = bounds.destRegion.x1();
933         GLint top    = bounds.destRegion.y0();
934         GLint bottom = bounds.destRegion.y1();
935 
936         GLint extraXOffset = 0;
937         if (left >= 0 && left < bounds.destBounds.width)
938         {
939             // Left edge is in-bounds
940             destOriginX = bounds.destRegion.x;
941         }
942         else if (right > 0 && right <= bounds.destBounds.width)
943         {
944             // Right edge is in-bounds
945             destOriginX = right - destClippedWidth;
946         }
947         else
948         {
949             // Region completely spans bounds
950             extraXOffset = (bounds.destRegion.width - destClippedWidth) / 2;
951             destOriginX  = bounds.destRegion.x + extraXOffset;
952         }
953 
954         GLint extraYOffset = 0;
955         if (top >= 0 && top < bounds.destBounds.height)
956         {
957             // Top edge is in-bounds
958             destOriginY = bounds.destRegion.y;
959         }
960         else if (bottom > 0 && bottom <= bounds.destBounds.height)
961         {
962             // Bottom edge is in-bounds
963             destOriginY = bottom - destClippedHeight;
964         }
965         else
966         {
967             // Region completely spans bounds
968             extraYOffset = (bounds.destRegion.height - destClippedHeight) / 2;
969             destOriginY  = bounds.destRegion.y + extraYOffset;
970         }
971 
972         // Offsets from the bottom left corner of the original region to
973         // the bottom left corner of the clipped region.
974         // This value (after it is scaled) is the respective offset we will apply
975         // to the src origin.
976 
977         CheckedNumeric<GLuint> checkedXOffset(destOriginX - bounds.destRegion.x - extraXOffset / 2);
978         CheckedNumeric<GLuint> checkedYOffset(destOriginY - bounds.destRegion.y - extraYOffset / 2);
979 
980         // if X/Y is reversed, use the top/right out-of-bounds region to compute
981         // the origin offset instead of the left/bottom out-of-bounds region
982         if (bounds.xFlipped)
983         {
984             checkedXOffset =
985                 (bounds.destRegion.x1() - (destOriginX + destClippedWidth) + extraXOffset / 2);
986         }
987         if (bounds.yFlipped)
988         {
989             checkedYOffset =
990                 (bounds.destRegion.y1() - (destOriginY + destClippedHeight) + extraYOffset / 2);
991         }
992 
993         // These offsets should never overflow
994         GLuint xOffset, yOffset;
995         if (!checkedXOffset.AssignIfValid(&xOffset) || !checkedYOffset.AssignIfValid(&yOffset))
996         {
997             UNREACHABLE();
998             return angle::Result::Stop;
999         }
1000 
1001         bounds.destRegion =
1002             gl::Rectangle(destOriginX, destOriginY, destClippedWidth, destClippedHeight);
1003 
1004         // Adjust the src region by the same factor
1005         bounds.sourceRegion = gl::Rectangle(bounds.sourceRegion.x + (xOffset >> destXHalvings),
1006                                             bounds.sourceRegion.y + (yOffset >> destYHalvings),
1007                                             bounds.sourceRegion.width >> destXHalvings,
1008                                             bounds.sourceRegion.height >> destYHalvings);
1009 
1010         // if the src was scaled to 0, set it to 1 so the src is non-empty
1011         if (bounds.sourceRegion.width == 0)
1012         {
1013             bounds.sourceRegion.width = 1;
1014         }
1015         if (bounds.sourceRegion.height == 0)
1016         {
1017             bounds.sourceRegion.height = 1;
1018         }
1019     }
1020 
1021     if (!bounds.sourceBounds.encloses(bounds.sourceRegion))
1022     {
1023         // sourceRegion is not within sourceBounds. We want to adjust it to a
1024         // reasonable size. This is done by halving the sourceRegion until it is at
1025         // most twice the size of the framebuffer. We cut it in half instead
1026         // of arbitrarily shrinking it to fit so that we don't end up with
1027         // non-power-of-two scale factors which could mess up pixel interpolation.
1028         // Naively clipping the source rect and then proportionally sizing the
1029         // dest rect yields incorrect results.
1030 
1031         GLuint sourceXHalvings = 0;
1032         GLuint sourceYHalvings = 0;
1033         GLint sourceOriginX    = bounds.sourceRegion.x;
1034         GLint sourceOriginY    = bounds.sourceRegion.y;
1035 
1036         GLint sourceClippedWidth = bounds.sourceRegion.width;
1037         while (sourceClippedWidth > 2 * bounds.sourceBounds.width)
1038         {
1039             sourceClippedWidth = sourceClippedWidth / 2;
1040             sourceXHalvings++;
1041         }
1042 
1043         GLint sourceClippedHeight = bounds.sourceRegion.height;
1044         while (sourceClippedHeight > 2 * bounds.sourceBounds.height)
1045         {
1046             sourceClippedHeight = sourceClippedHeight / 2;
1047             sourceYHalvings++;
1048         }
1049 
1050         // Before this block, we check that the two rectangles intersect.
1051         // Now, compute the location of a new region origin such that we use the
1052         // scaled dimensions but the new region has the same intersection as the
1053         // original region.
1054 
1055         GLint left   = bounds.sourceRegion.x0();
1056         GLint right  = bounds.sourceRegion.x1();
1057         GLint top    = bounds.sourceRegion.y0();
1058         GLint bottom = bounds.sourceRegion.y1();
1059 
1060         GLint extraXOffset = 0;
1061         if (left >= 0 && left < bounds.sourceBounds.width)
1062         {
1063             // Left edge is in-bounds
1064             sourceOriginX = bounds.sourceRegion.x;
1065         }
1066         else if (right > 0 && right <= bounds.sourceBounds.width)
1067         {
1068             // Right edge is in-bounds
1069             sourceOriginX = right - sourceClippedWidth;
1070         }
1071         else
1072         {
1073             // Region completely spans bounds
1074             extraXOffset  = (bounds.sourceRegion.width - sourceClippedWidth) / 2;
1075             sourceOriginX = bounds.sourceRegion.x + extraXOffset;
1076         }
1077 
1078         GLint extraYOffset = 0;
1079         if (top >= 0 && top < bounds.sourceBounds.height)
1080         {
1081             // Top edge is in-bounds
1082             sourceOriginY = bounds.sourceRegion.y;
1083         }
1084         else if (bottom > 0 && bottom <= bounds.sourceBounds.height)
1085         {
1086             // Bottom edge is in-bounds
1087             sourceOriginY = bottom - sourceClippedHeight;
1088         }
1089         else
1090         {
1091             // Region completely spans bounds
1092             extraYOffset  = (bounds.sourceRegion.height - sourceClippedHeight) / 2;
1093             sourceOriginY = bounds.sourceRegion.y + extraYOffset;
1094         }
1095 
1096         // Offsets from the bottom left corner of the original region to
1097         // the bottom left corner of the clipped region.
1098         // This value (after it is scaled) is the respective offset we will apply
1099         // to the dest origin.
1100 
1101         CheckedNumeric<GLuint> checkedXOffset(sourceOriginX - bounds.sourceRegion.x -
1102                                               extraXOffset / 2);
1103         CheckedNumeric<GLuint> checkedYOffset(sourceOriginY - bounds.sourceRegion.y -
1104                                               extraYOffset / 2);
1105 
1106         // if X/Y is reversed, use the top/right out-of-bounds region to compute
1107         // the origin offset instead of the left/bottom out-of-bounds region
1108         if (bounds.xFlipped)
1109         {
1110             checkedXOffset = (bounds.sourceRegion.x1() - (sourceOriginX + sourceClippedWidth) +
1111                               extraXOffset / 2);
1112         }
1113         if (bounds.yFlipped)
1114         {
1115             checkedYOffset = (bounds.sourceRegion.y1() - (sourceOriginY + sourceClippedHeight) +
1116                               extraYOffset / 2);
1117         }
1118 
1119         // These offsets should never overflow
1120         GLuint xOffset, yOffset;
1121         if (!checkedXOffset.AssignIfValid(&xOffset) || !checkedYOffset.AssignIfValid(&yOffset))
1122         {
1123             UNREACHABLE();
1124             return angle::Result::Stop;
1125         }
1126 
1127         bounds.sourceRegion =
1128             gl::Rectangle(sourceOriginX, sourceOriginY, sourceClippedWidth, sourceClippedHeight);
1129 
1130         // Adjust the dest region by the same factor
1131         bounds.destRegion = gl::Rectangle(bounds.destRegion.x + (xOffset >> sourceXHalvings),
1132                                           bounds.destRegion.y + (yOffset >> sourceYHalvings),
1133                                           bounds.destRegion.width >> sourceXHalvings,
1134                                           bounds.destRegion.height >> sourceYHalvings);
1135     }
1136     // Set the src and dst endpoints. If they were previously flipped,
1137     // set them as flipped.
1138     *newSourceArea = bounds.sourceRegion.flip(sourceArea.isReversedX(), sourceArea.isReversedY());
1139     *newDestArea   = bounds.destRegion.flip(destArea.isReversedX(), destArea.isReversedY());
1140 
1141     return angle::Result::Continue;
1142 }
1143 
clipSrcRegion(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,gl::Rectangle * newSourceArea,gl::Rectangle * newDestArea)1144 angle::Result FramebufferGL::clipSrcRegion(const gl::Context *context,
1145                                            const gl::Rectangle &sourceArea,
1146                                            const gl::Rectangle &destArea,
1147                                            gl::Rectangle *newSourceArea,
1148                                            gl::Rectangle *newDestArea)
1149 {
1150     BlitFramebufferBounds bounds = GetBlitFramebufferBounds(context, sourceArea, destArea);
1151 
1152     if (bounds.destRegion.width == 0 || bounds.sourceRegion.width == 0 ||
1153         bounds.destRegion.height == 0 || bounds.sourceRegion.height == 0)
1154     {
1155         return angle::Result::Stop;
1156     }
1157     if (!ClipRectangle(bounds.destBounds, bounds.destRegion, nullptr))
1158     {
1159         return angle::Result::Stop;
1160     }
1161 
1162     if (!bounds.sourceBounds.encloses(bounds.sourceRegion))
1163     {
1164         // If pixels lying outside the read framebuffer, adjust src region
1165         // and dst region to appropriate in-bounds regions respectively.
1166         gl::Rectangle realSourceRegion;
1167         if (!ClipRectangle(bounds.sourceRegion, bounds.sourceBounds, &realSourceRegion))
1168         {
1169             return angle::Result::Stop;
1170         }
1171         GLuint xOffset = realSourceRegion.x - bounds.sourceRegion.x;
1172         GLuint yOffset = realSourceRegion.y - bounds.sourceRegion.y;
1173 
1174         // if X/Y is reversed, use the top/right out-of-bounds region for mapping
1175         // to dst region, instead of left/bottom out-of-bounds region for mapping.
1176         if (bounds.xFlipped)
1177         {
1178             xOffset = bounds.sourceRegion.x1() - realSourceRegion.x1();
1179         }
1180         if (bounds.yFlipped)
1181         {
1182             yOffset = bounds.sourceRegion.y1() - realSourceRegion.y1();
1183         }
1184 
1185         GLfloat destMappingWidth = static_cast<GLfloat>(realSourceRegion.width) *
1186                                    bounds.destRegion.width / bounds.sourceRegion.width;
1187         GLfloat destMappingHeight = static_cast<GLfloat>(realSourceRegion.height) *
1188                                     bounds.destRegion.height / bounds.sourceRegion.height;
1189         GLfloat destMappingXOffset =
1190             static_cast<GLfloat>(xOffset) * bounds.destRegion.width / bounds.sourceRegion.width;
1191         GLfloat destMappingYOffset =
1192             static_cast<GLfloat>(yOffset) * bounds.destRegion.height / bounds.sourceRegion.height;
1193 
1194         GLuint destMappingX0 =
1195             static_cast<GLuint>(std::round(bounds.destRegion.x + destMappingXOffset));
1196         GLuint destMappingY0 =
1197             static_cast<GLuint>(std::round(bounds.destRegion.y + destMappingYOffset));
1198 
1199         GLuint destMappingX1 = static_cast<GLuint>(
1200             std::round(bounds.destRegion.x + destMappingXOffset + destMappingWidth));
1201         GLuint destMappingY1 = static_cast<GLuint>(
1202             std::round(bounds.destRegion.y + destMappingYOffset + destMappingHeight));
1203 
1204         bounds.destRegion =
1205             gl::Rectangle(destMappingX0, destMappingY0, destMappingX1 - destMappingX0,
1206                           destMappingY1 - destMappingY0);
1207 
1208         bounds.sourceRegion = realSourceRegion;
1209     }
1210     // Set the src and dst endpoints. If they were previously flipped,
1211     // set them as flipped.
1212     *newSourceArea = bounds.sourceRegion.flip(sourceArea.isReversedX(), sourceArea.isReversedY());
1213     *newDestArea   = bounds.destRegion.flip(destArea.isReversedX(), destArea.isReversedY());
1214 
1215     return angle::Result::Continue;
1216 }
1217 
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const1218 angle::Result FramebufferGL::getSamplePosition(const gl::Context *context,
1219                                                size_t index,
1220                                                GLfloat *xy) const
1221 {
1222     const FunctionsGL *functions = GetFunctionsGL(context);
1223     StateManagerGL *stateManager = GetStateManagerGL(context);
1224 
1225     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
1226     functions->getMultisamplefv(GL_SAMPLE_POSITION, static_cast<GLuint>(index), xy);
1227     return angle::Result::Continue;
1228 }
1229 
shouldSyncStateBeforeCheckStatus() const1230 bool FramebufferGL::shouldSyncStateBeforeCheckStatus() const
1231 {
1232     return true;
1233 }
1234 
checkStatus(const gl::Context * context) const1235 gl::FramebufferStatus FramebufferGL::checkStatus(const gl::Context *context) const
1236 {
1237     const FunctionsGL *functions = GetFunctionsGL(context);
1238     StateManagerGL *stateManager = GetStateManagerGL(context);
1239 
1240     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
1241     GLenum status = functions->checkFramebufferStatus(GL_FRAMEBUFFER);
1242     if (status != GL_FRAMEBUFFER_COMPLETE)
1243     {
1244         WARN() << "GL framebuffer returned incomplete: " << gl::FmtHex(status);
1245         return gl::FramebufferStatus::Incomplete(GL_FRAMEBUFFER_UNSUPPORTED,
1246                                                  gl::err::kFramebufferIncompleteDriverUnsupported);
1247     }
1248 
1249     return gl::FramebufferStatus::Complete();
1250 }
1251 
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)1252 angle::Result FramebufferGL::syncState(const gl::Context *context,
1253                                        GLenum binding,
1254                                        const gl::Framebuffer::DirtyBits &dirtyBits,
1255                                        gl::Command command)
1256 {
1257     // Don't need to sync state for the default FBO.
1258     if (isDefault())
1259     {
1260         return angle::Result::Continue;
1261     }
1262 
1263     const FunctionsGL *functions = GetFunctionsGL(context);
1264     StateManagerGL *stateManager = GetStateManagerGL(context);
1265 
1266     stateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
1267 
1268     // A pointer to one of the attachments for which the texture or the render buffer is not zero.
1269     const FramebufferAttachment *attachment = nullptr;
1270 
1271     for (auto dirtyBit : dirtyBits)
1272     {
1273         switch (dirtyBit)
1274         {
1275             case Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
1276             {
1277                 const FramebufferAttachment *newAttachment = mState.getDepthAttachment();
1278                 BindFramebufferAttachment(functions, GL_DEPTH_ATTACHMENT, newAttachment,
1279                                           GetFeaturesGL(context));
1280                 if (newAttachment)
1281                 {
1282                     attachment = newAttachment;
1283                 }
1284                 break;
1285             }
1286             case Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
1287             {
1288                 const FramebufferAttachment *newAttachment = mState.getStencilAttachment();
1289                 BindFramebufferAttachment(functions, GL_STENCIL_ATTACHMENT, newAttachment,
1290                                           GetFeaturesGL(context));
1291                 if (newAttachment)
1292                 {
1293                     attachment = newAttachment;
1294                 }
1295                 break;
1296             }
1297             case Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
1298             {
1299                 const auto &drawBuffers = mState.getDrawBufferStates();
1300                 functions->drawBuffers(static_cast<GLsizei>(drawBuffers.size()),
1301                                        drawBuffers.data());
1302                 mAppliedEnabledDrawBuffers = mState.getEnabledDrawBuffers();
1303                 break;
1304             }
1305             case Framebuffer::DIRTY_BIT_READ_BUFFER:
1306                 functions->readBuffer(mState.getReadBufferState());
1307                 break;
1308             case Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
1309                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_WIDTH,
1310                                                  mState.getDefaultWidth());
1311                 break;
1312             case Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
1313                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_HEIGHT,
1314                                                  mState.getDefaultHeight());
1315                 break;
1316             case Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
1317                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_SAMPLES,
1318                                                  mState.getDefaultSamples());
1319                 break;
1320             case Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
1321                 functions->framebufferParameteri(
1322                     GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS,
1323                     gl::ConvertToGLBoolean(mState.getDefaultFixedSampleLocations()));
1324                 break;
1325             case Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
1326                 functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_DEFAULT_LAYERS_EXT,
1327                                                  mState.getDefaultLayers());
1328                 break;
1329             case Framebuffer::DIRTY_BIT_FLIP_Y:
1330                 ASSERT(functions->framebufferParameteri || functions->framebufferParameteriMESA);
1331                 if (functions->framebufferParameteri)
1332                 {
1333                     functions->framebufferParameteri(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA,
1334                                                      gl::ConvertToGLBoolean(mState.getFlipY()));
1335                 }
1336                 else
1337                 {
1338                     functions->framebufferParameteriMESA(GL_FRAMEBUFFER, GL_FRAMEBUFFER_FLIP_Y_MESA,
1339                                                          gl::ConvertToGLBoolean(mState.getFlipY()));
1340                 }
1341                 break;
1342             default:
1343             {
1344                 static_assert(Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
1345                 if (dirtyBit < Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
1346                 {
1347                     size_t index =
1348                         static_cast<size_t>(dirtyBit - Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
1349                     const FramebufferAttachment *newAttachment = mState.getColorAttachment(index);
1350                     BindFramebufferAttachment(functions,
1351                                               static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + index),
1352                                               newAttachment, GetFeaturesGL(context));
1353                     if (newAttachment)
1354                     {
1355                         attachment = newAttachment;
1356                     }
1357 
1358                     // Hiding an alpha channel is only supported when it's the first attachment
1359                     // currently. Assert that these emulated textures are not bound to a framebuffer
1360                     // using MRT.
1361                     if (index == 0)
1362                     {
1363                         mHasEmulatedAlphaAttachment =
1364                             IsEmulatedAlphaChannelTextureAttachment(attachment);
1365                     }
1366                     ASSERT(index == 0 || !IsEmulatedAlphaChannelTextureAttachment(attachment));
1367                 }
1368                 break;
1369             }
1370         }
1371     }
1372 
1373     if (attachment && mState.id() == context->getState().getDrawFramebuffer()->id())
1374     {
1375         stateManager->updateMultiviewBaseViewLayerIndexUniform(context->getState().getProgram(),
1376                                                                getState());
1377     }
1378 
1379     return angle::Result::Continue;
1380 }
1381 
updateDefaultFramebufferID(GLuint framebufferID)1382 void FramebufferGL::updateDefaultFramebufferID(GLuint framebufferID)
1383 {
1384     // We only update framebufferID for a default frambuffer, and the framebufferID is created
1385     // externally. ANGLE doesn't owne it.
1386     ASSERT(isDefault());
1387     mFramebufferID = framebufferID;
1388 }
1389 
hasEmulatedAlphaChannelTextureAttachment() const1390 bool FramebufferGL::hasEmulatedAlphaChannelTextureAttachment() const
1391 {
1392     return mHasEmulatedAlphaAttachment;
1393 }
1394 
syncClearState(const gl::Context * context,GLbitfield mask)1395 void FramebufferGL::syncClearState(const gl::Context *context, GLbitfield mask)
1396 {
1397     StateManagerGL *stateManager      = GetStateManagerGL(context);
1398     const angle::FeaturesGL &features = GetFeaturesGL(context);
1399 
1400     // Clip origin must not affect scissor box but some drivers flip it for clear ops.
1401     if (context->getState().isScissorTestEnabled())
1402     {
1403         stateManager->setClipControl(ClipOrigin::LowerLeft, ClipDepthMode::NegativeOneToOne);
1404     }
1405 
1406     if (features.doesSRGBClearsOnLinearFramebufferAttachments.enabled &&
1407         (mask & GL_COLOR_BUFFER_BIT) != 0 && !isDefault())
1408     {
1409         bool hasSRGBAttachment = false;
1410         for (const auto &attachment : mState.getColorAttachments())
1411         {
1412             if (attachment.isAttached() && attachment.getColorEncoding() == GL_SRGB)
1413             {
1414                 hasSRGBAttachment = true;
1415                 break;
1416             }
1417         }
1418 
1419         stateManager->setFramebufferSRGBEnabled(context, hasSRGBAttachment);
1420     }
1421     else
1422     {
1423         stateManager->setFramebufferSRGBEnabled(context, !isDefault());
1424     }
1425 }
1426 
syncClearBufferState(const gl::Context * context,GLenum buffer,GLint drawBuffer)1427 void FramebufferGL::syncClearBufferState(const gl::Context *context,
1428                                          GLenum buffer,
1429                                          GLint drawBuffer)
1430 {
1431     StateManagerGL *stateManager      = GetStateManagerGL(context);
1432     const angle::FeaturesGL &features = GetFeaturesGL(context);
1433 
1434     // Clip origin must not affect scissor box but some drivers flip it for clear ops.
1435     if (context->getState().isScissorTestEnabled())
1436     {
1437         stateManager->setClipControl(ClipOrigin::LowerLeft, ClipDepthMode::NegativeOneToOne);
1438     }
1439 
1440     if (features.doesSRGBClearsOnLinearFramebufferAttachments.enabled && buffer == GL_COLOR &&
1441         !isDefault())
1442     {
1443         // If doing a clear on a color buffer, set SRGB blend enabled only if the color buffer
1444         // is an SRGB format.
1445         const auto &drawbufferState  = mState.getDrawBufferStates();
1446         const auto &colorAttachments = mState.getColorAttachments();
1447 
1448         const FramebufferAttachment *attachment = nullptr;
1449         if (drawbufferState[drawBuffer] >= GL_COLOR_ATTACHMENT0 &&
1450             drawbufferState[drawBuffer] < GL_COLOR_ATTACHMENT0 + colorAttachments.size())
1451         {
1452             size_t attachmentIdx =
1453                 static_cast<size_t>(drawbufferState[drawBuffer] - GL_COLOR_ATTACHMENT0);
1454             attachment = &colorAttachments[attachmentIdx];
1455         }
1456 
1457         if (attachment != nullptr)
1458         {
1459             stateManager->setFramebufferSRGBEnabled(context,
1460                                                     attachment->getColorEncoding() == GL_SRGB);
1461         }
1462     }
1463     else
1464     {
1465         stateManager->setFramebufferSRGBEnabled(context, !isDefault());
1466     }
1467 }
1468 
modifyInvalidateAttachmentsForEmulatedDefaultFBO(size_t count,const GLenum * attachments,std::vector<GLenum> * modifiedAttachments) const1469 bool FramebufferGL::modifyInvalidateAttachmentsForEmulatedDefaultFBO(
1470     size_t count,
1471     const GLenum *attachments,
1472     std::vector<GLenum> *modifiedAttachments) const
1473 {
1474     bool needsModification = isDefault() && mFramebufferID != 0;
1475     if (!needsModification)
1476     {
1477         return false;
1478     }
1479 
1480     modifiedAttachments->resize(count);
1481     for (size_t i = 0; i < count; i++)
1482     {
1483         switch (attachments[i])
1484         {
1485             case GL_COLOR:
1486                 (*modifiedAttachments)[i] = GL_COLOR_ATTACHMENT0;
1487                 break;
1488 
1489             case GL_DEPTH:
1490                 (*modifiedAttachments)[i] = GL_DEPTH_ATTACHMENT;
1491                 break;
1492 
1493             case GL_STENCIL:
1494                 (*modifiedAttachments)[i] = GL_STENCIL_ATTACHMENT;
1495                 break;
1496 
1497             default:
1498                 UNREACHABLE();
1499                 break;
1500         }
1501     }
1502 
1503     return true;
1504 }
1505 
readPixelsRowByRow(const gl::Context * context,const gl::Rectangle & area,GLenum originalReadFormat,GLenum format,GLenum type,const gl::PixelPackState & pack,GLubyte * pixels) const1506 angle::Result FramebufferGL::readPixelsRowByRow(const gl::Context *context,
1507                                                 const gl::Rectangle &area,
1508                                                 GLenum originalReadFormat,
1509                                                 GLenum format,
1510                                                 GLenum type,
1511                                                 const gl::PixelPackState &pack,
1512                                                 GLubyte *pixels) const
1513 {
1514     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1515     const FunctionsGL *functions      = GetFunctionsGL(context);
1516     StateManagerGL *stateManager      = GetStateManagerGL(context);
1517     GLubyte *originalReadFormatPixels = pixels;
1518 
1519     const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
1520 
1521     GLuint rowBytes = 0;
1522     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, pack.alignment,
1523                                                             pack.rowLength, &rowBytes));
1524     GLuint skipBytes = 0;
1525     ANGLE_CHECK_GL_MATH(contextGL,
1526                         glFormat.computeSkipBytes(type, rowBytes, 0, pack, false, &skipBytes));
1527 
1528     ScopedEXTTextureNorm16ReadbackWorkaround workaround;
1529     angle::Result result =
1530         workaround.Initialize(context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1531                               glFormat.computePixelBytes(type), pixels);
1532     if (result != angle::Result::Continue)
1533     {
1534         return result;
1535     }
1536 
1537     gl::PixelPackState directPack;
1538     directPack.alignment = 1;
1539     ANGLE_TRY(stateManager->setPixelPackState(context, directPack));
1540 
1541     GLubyte *readbackPixels = workaround.Pixels();
1542     readbackPixels += skipBytes;
1543     for (GLint y = area.y; y < area.y + area.height; ++y)
1544     {
1545         ANGLE_GL_TRY(context,
1546                      functions->readPixels(area.x, y, area.width, 1, format, type, readbackPixels));
1547         readbackPixels += rowBytes;
1548     }
1549 
1550     if (workaround.IsEnabled())
1551     {
1552         return RearrangeEXTTextureNorm16Pixels(
1553             context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1554             glFormat.computePixelBytes(type), pack, originalReadFormatPixels, workaround.Pixels());
1555     }
1556 
1557     return angle::Result::Continue;
1558 }
1559 
readPixelsAllAtOnce(const gl::Context * context,const gl::Rectangle & area,GLenum originalReadFormat,GLenum format,GLenum type,const gl::PixelPackState & pack,GLubyte * pixels,bool readLastRowSeparately) const1560 angle::Result FramebufferGL::readPixelsAllAtOnce(const gl::Context *context,
1561                                                  const gl::Rectangle &area,
1562                                                  GLenum originalReadFormat,
1563                                                  GLenum format,
1564                                                  GLenum type,
1565                                                  const gl::PixelPackState &pack,
1566                                                  GLubyte *pixels,
1567                                                  bool readLastRowSeparately) const
1568 {
1569     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1570     const FunctionsGL *functions      = GetFunctionsGL(context);
1571     StateManagerGL *stateManager      = GetStateManagerGL(context);
1572     GLubyte *originalReadFormatPixels = pixels;
1573 
1574     const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
1575 
1576     GLuint rowBytes = 0;
1577     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, pack.alignment,
1578                                                             pack.rowLength, &rowBytes));
1579     GLuint skipBytes = 0;
1580     ANGLE_CHECK_GL_MATH(contextGL,
1581                         glFormat.computeSkipBytes(type, rowBytes, 0, pack, false, &skipBytes));
1582 
1583     ScopedEXTTextureNorm16ReadbackWorkaround workaround;
1584     angle::Result result =
1585         workaround.Initialize(context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1586                               glFormat.computePixelBytes(type), pixels);
1587     if (result != angle::Result::Continue)
1588     {
1589         return result;
1590     }
1591 
1592     GLint height = area.height - readLastRowSeparately;
1593     if (height > 0)
1594     {
1595         ANGLE_TRY(stateManager->setPixelPackState(context, pack));
1596         ANGLE_GL_TRY(context, functions->readPixels(area.x, area.y, area.width, height, format,
1597                                                     type, workaround.Pixels()));
1598     }
1599 
1600     if (readLastRowSeparately)
1601     {
1602         gl::PixelPackState directPack;
1603         directPack.alignment = 1;
1604         ANGLE_TRY(stateManager->setPixelPackState(context, directPack));
1605 
1606         GLubyte *readbackPixels = workaround.Pixels();
1607         readbackPixels += skipBytes + (area.height - 1) * rowBytes;
1608         ANGLE_GL_TRY(context, functions->readPixels(area.x, area.y + area.height - 1, area.width, 1,
1609                                                     format, type, readbackPixels));
1610     }
1611 
1612     if (workaround.IsEnabled())
1613     {
1614         return RearrangeEXTTextureNorm16Pixels(
1615             context, area, originalReadFormat, format, type, skipBytes, rowBytes,
1616             glFormat.computePixelBytes(type), pack, originalReadFormatPixels, workaround.Pixels());
1617     }
1618 
1619     return angle::Result::Continue;
1620 }
1621 }  // namespace rx
1622