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