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