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