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