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