xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/gl/BlitGL.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 // BlitGL.cpp: Implements the BlitGL class, a helper for blitting textures
8 
9 #include "libANGLE/renderer/gl/BlitGL.h"
10 
11 #include "common/FixedVector.h"
12 #include "common/utilities.h"
13 #include "common/vector_utils.h"
14 #include "image_util/copyimage.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Framebuffer.h"
17 #include "libANGLE/formatutils.h"
18 #include "libANGLE/renderer/Format.h"
19 #include "libANGLE/renderer/gl/ContextGL.h"
20 #include "libANGLE/renderer/gl/FramebufferGL.h"
21 #include "libANGLE/renderer/gl/FunctionsGL.h"
22 #include "libANGLE/renderer/gl/RenderbufferGL.h"
23 #include "libANGLE/renderer/gl/StateManagerGL.h"
24 #include "libANGLE/renderer/gl/TextureGL.h"
25 #include "libANGLE/renderer/gl/formatutilsgl.h"
26 #include "libANGLE/renderer/gl/renderergl_utils.h"
27 #include "libANGLE/renderer/renderer_utils.h"
28 #include "platform/autogen/FeaturesGL_autogen.h"
29 
30 using angle::Vector2;
31 
32 namespace rx
33 {
34 
35 namespace
36 {
37 
CheckCompileStatus(const gl::Context * context,const rx::FunctionsGL * functions,GLuint shader)38 angle::Result CheckCompileStatus(const gl::Context *context,
39                                  const rx::FunctionsGL *functions,
40                                  GLuint shader)
41 {
42     GLint compileStatus = GL_FALSE;
43     ANGLE_GL_TRY(context, functions->getShaderiv(shader, GL_COMPILE_STATUS, &compileStatus));
44 
45     ASSERT(compileStatus == GL_TRUE);
46     ANGLE_CHECK(GetImplAs<ContextGL>(context), compileStatus == GL_TRUE,
47                 "Failed to compile internal blit shader.", GL_OUT_OF_MEMORY);
48 
49     return angle::Result::Continue;
50 }
51 
CheckLinkStatus(const gl::Context * context,const rx::FunctionsGL * functions,GLuint program)52 angle::Result CheckLinkStatus(const gl::Context *context,
53                               const rx::FunctionsGL *functions,
54                               GLuint program)
55 {
56     GLint linkStatus = GL_FALSE;
57     ANGLE_GL_TRY(context, functions->getProgramiv(program, GL_LINK_STATUS, &linkStatus));
58     ASSERT(linkStatus == GL_TRUE);
59     ANGLE_CHECK(GetImplAs<ContextGL>(context), linkStatus == GL_TRUE,
60                 "Failed to link internal blit program.", GL_OUT_OF_MEMORY);
61 
62     return angle::Result::Continue;
63 }
64 
65 class [[nodiscard]] ScopedGLState : angle::NonCopyable
66 {
67   public:
68     enum
69     {
70         KEEP_SCISSOR = 1,
71     };
72 
ScopedGLState()73     ScopedGLState() {}
74 
~ScopedGLState()75     ~ScopedGLState() { ASSERT(mExited); }
76 
enter(const gl::Context * context,gl::Rectangle viewport,int keepState=0)77     angle::Result enter(const gl::Context *context, gl::Rectangle viewport, int keepState = 0)
78     {
79         ContextGL *contextGL         = GetImplAs<ContextGL>(context);
80         StateManagerGL *stateManager = contextGL->getStateManager();
81 
82         if (!(keepState & KEEP_SCISSOR))
83         {
84             stateManager->setScissorTestEnabled(false);
85         }
86         stateManager->setViewport(viewport);
87         stateManager->setDepthRange(0.0f, 1.0f);
88         stateManager->setClipControl(gl::ClipOrigin::LowerLeft,
89                                      gl::ClipDepthMode::NegativeOneToOne);
90         stateManager->setClipDistancesEnable(gl::ClipDistanceEnableBits());
91         stateManager->setDepthClampEnabled(false);
92         stateManager->setBlendEnabled(false);
93         stateManager->setColorMask(true, true, true, true);
94         stateManager->setSampleAlphaToCoverageEnabled(false);
95         stateManager->setSampleCoverageEnabled(false);
96         stateManager->setDepthTestEnabled(false);
97         stateManager->setStencilTestEnabled(false);
98         stateManager->setCullFaceEnabled(false);
99         stateManager->setPolygonMode(gl::PolygonMode::Fill);
100         stateManager->setPolygonOffsetPointEnabled(false);
101         stateManager->setPolygonOffsetLineEnabled(false);
102         stateManager->setPolygonOffsetFillEnabled(false);
103         stateManager->setRasterizerDiscardEnabled(false);
104         stateManager->setLogicOpEnabled(false);
105 
106         stateManager->pauseTransformFeedback();
107         return stateManager->pauseAllQueries(context);
108     }
109 
exit(const gl::Context * context)110     angle::Result exit(const gl::Context *context)
111     {
112         mExited = true;
113 
114         ContextGL *contextGL         = GetImplAs<ContextGL>(context);
115         StateManagerGL *stateManager = contextGL->getStateManager();
116 
117         // XFB resuming will be done automatically
118         return stateManager->resumeAllQueries(context);
119     }
120 
willUseTextureUnit(const gl::Context * context,int unit)121     void willUseTextureUnit(const gl::Context *context, int unit)
122     {
123         ContextGL *contextGL = GetImplAs<ContextGL>(context);
124 
125         if (contextGL->getFunctions()->bindSampler)
126         {
127             contextGL->getStateManager()->bindSampler(unit, 0);
128         }
129     }
130 
131   private:
132     bool mExited = false;
133 };
134 
SetClearState(StateManagerGL * stateManager,bool colorClear,bool depthClear,bool stencilClear,GLbitfield * outClearMask)135 angle::Result SetClearState(StateManagerGL *stateManager,
136                             bool colorClear,
137                             bool depthClear,
138                             bool stencilClear,
139                             GLbitfield *outClearMask)
140 {
141     *outClearMask = 0;
142     if (colorClear)
143     {
144         stateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 0.0f));
145         stateManager->setColorMask(true, true, true, true);
146         *outClearMask |= GL_COLOR_BUFFER_BIT;
147     }
148     if (depthClear)
149     {
150         stateManager->setDepthMask(true);
151         stateManager->setClearDepth(1.0f);
152         *outClearMask |= GL_DEPTH_BUFFER_BIT;
153     }
154     if (stencilClear)
155     {
156         stateManager->setClearStencil(0);
157         *outClearMask |= GL_STENCIL_BUFFER_BIT;
158     }
159 
160     stateManager->setScissorTestEnabled(false);
161 
162     return angle::Result::Continue;
163 }
164 
165 using ClearBindTargetVector = angle::FixedVector<GLenum, 3>;
166 
PrepareForClear(StateManagerGL * stateManager,GLenum sizedInternalFormat,ClearBindTargetVector * outBindtargets,ClearBindTargetVector * outUnbindTargets,GLbitfield * outClearMask)167 angle::Result PrepareForClear(StateManagerGL *stateManager,
168                               GLenum sizedInternalFormat,
169                               ClearBindTargetVector *outBindtargets,
170                               ClearBindTargetVector *outUnbindTargets,
171                               GLbitfield *outClearMask)
172 {
173     const gl::InternalFormat &internalFormatInfo =
174         gl::GetSizedInternalFormatInfo(sizedInternalFormat);
175     bool bindDepth   = internalFormatInfo.depthBits > 0;
176     bool bindStencil = internalFormatInfo.stencilBits > 0;
177     bool bindColor   = !bindDepth && !bindStencil;
178 
179     outBindtargets->clear();
180     if (bindColor)
181     {
182         outBindtargets->push_back(GL_COLOR_ATTACHMENT0);
183     }
184     else
185     {
186         outUnbindTargets->push_back(GL_COLOR_ATTACHMENT0);
187     }
188     if (bindDepth)
189     {
190         outBindtargets->push_back(GL_DEPTH_ATTACHMENT);
191     }
192     else
193     {
194         outUnbindTargets->push_back(GL_DEPTH_ATTACHMENT);
195     }
196     if (bindStencil)
197     {
198         outBindtargets->push_back(GL_STENCIL_ATTACHMENT);
199     }
200     else
201     {
202         outUnbindTargets->push_back(GL_STENCIL_ATTACHMENT);
203     }
204 
205     ANGLE_TRY(SetClearState(stateManager, bindColor, bindDepth, bindStencil, outClearMask));
206 
207     return angle::Result::Continue;
208 }
209 
UnbindAttachment(const gl::Context * context,const FunctionsGL * functions,GLenum framebufferTarget,GLenum attachment)210 angle::Result UnbindAttachment(const gl::Context *context,
211                                const FunctionsGL *functions,
212                                GLenum framebufferTarget,
213                                GLenum attachment)
214 {
215     // Always use framebufferTexture2D as a workaround for an Nvidia driver bug. See
216     // https://anglebug.com/42264072 and FeaturesGL.alwaysUnbindFramebufferTexture2D
217     ANGLE_GL_TRY(context,
218                  functions->framebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, 0, 0));
219 
220     return angle::Result::Continue;
221 }
222 
UnbindAttachments(const gl::Context * context,const FunctionsGL * functions,GLenum framebufferTarget,const ClearBindTargetVector & bindTargets)223 angle::Result UnbindAttachments(const gl::Context *context,
224                                 const FunctionsGL *functions,
225                                 GLenum framebufferTarget,
226                                 const ClearBindTargetVector &bindTargets)
227 {
228     for (GLenum bindTarget : bindTargets)
229     {
230         ANGLE_TRY(UnbindAttachment(context, functions, framebufferTarget, bindTarget));
231     }
232     return angle::Result::Continue;
233 }
234 
CheckIfAttachmentNeedsClearing(const gl::Context * context,const gl::FramebufferAttachment * attachment,bool * needsClearInit)235 angle::Result CheckIfAttachmentNeedsClearing(const gl::Context *context,
236                                              const gl::FramebufferAttachment *attachment,
237                                              bool *needsClearInit)
238 {
239     if (attachment->initState() == gl::InitState::Initialized)
240     {
241         *needsClearInit = false;
242         return angle::Result::Continue;
243     }
244 
245     // Special case for 2D array and 3D textures. The init state tracks initialization for all
246     // layers but only one will be cleared by a clear call. Initialize those entire textures
247     // here.
248     if (attachment->type() == GL_TEXTURE &&
249         (attachment->getTextureImageIndex().getTarget() == gl::TextureTarget::_2DArray ||
250          attachment->getTextureImageIndex().getTarget() == gl::TextureTarget::_3D))
251     {
252         ANGLE_TRY(attachment->initializeContents(context));
253         *needsClearInit = false;
254         return angle::Result::Continue;
255     }
256 
257     *needsClearInit = true;
258     return angle::Result::Continue;
259 }
260 
261 }  // anonymous namespace
262 
BlitGL(const FunctionsGL * functions,const angle::FeaturesGL & features,StateManagerGL * stateManager)263 BlitGL::BlitGL(const FunctionsGL *functions,
264                const angle::FeaturesGL &features,
265                StateManagerGL *stateManager)
266     : mFunctions(functions),
267       mFeatures(features),
268       mStateManager(stateManager),
269       mScratchFBO(0),
270       mVAO(0),
271       mVertexBuffer(0)
272 {
273     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
274     {
275         mScratchTextures[i] = 0;
276     }
277 
278     ASSERT(mFunctions);
279     ASSERT(mStateManager);
280 }
281 
~BlitGL()282 BlitGL::~BlitGL()
283 {
284     for (const auto &blitProgram : mBlitPrograms)
285     {
286         mStateManager->deleteProgram(blitProgram.second.program);
287     }
288     mBlitPrograms.clear();
289 
290     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
291     {
292         if (mScratchTextures[i] != 0)
293         {
294             mStateManager->deleteTexture(mScratchTextures[i]);
295             mScratchTextures[i] = 0;
296         }
297     }
298 
299     if (mScratchFBO != 0)
300     {
301         mStateManager->deleteFramebuffer(mScratchFBO);
302         mScratchFBO = 0;
303     }
304 
305     if (mOwnsVAOState)
306     {
307         mStateManager->deleteVertexArray(mVAO);
308         SafeDelete(mVAOState);
309         mVAO = 0;
310     }
311 }
312 
copyImageToLUMAWorkaroundTexture(const gl::Context * context,GLuint texture,gl::TextureType textureType,gl::TextureTarget target,GLenum lumaFormat,size_t level,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)313 angle::Result BlitGL::copyImageToLUMAWorkaroundTexture(const gl::Context *context,
314                                                        GLuint texture,
315                                                        gl::TextureType textureType,
316                                                        gl::TextureTarget target,
317                                                        GLenum lumaFormat,
318                                                        size_t level,
319                                                        const gl::Rectangle &sourceArea,
320                                                        GLenum internalFormat,
321                                                        gl::Framebuffer *source)
322 {
323     mStateManager->bindTexture(textureType, texture);
324 
325     // Allocate the texture memory
326     GLenum format   = gl::GetUnsizedFormat(internalFormat);
327     GLenum readType = source->getImplementationColorReadType(context);
328 
329     // getImplementationColorReadType aligns the type with ES client version
330     if (readType == GL_HALF_FLOAT_OES && mFunctions->standard == STANDARD_GL_DESKTOP)
331     {
332         readType = GL_HALF_FLOAT;
333     }
334 
335     gl::PixelUnpackState unpack;
336     ANGLE_TRY(mStateManager->setPixelUnpackState(context, unpack));
337     ANGLE_TRY(mStateManager->setPixelUnpackBuffer(
338         context, context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack)));
339     ANGLE_GL_TRY_ALWAYS_CHECK(
340         context,
341         mFunctions->texImage2D(ToGLenum(target), static_cast<GLint>(level), internalFormat,
342                                sourceArea.width, sourceArea.height, 0, format, readType, nullptr));
343 
344     return copySubImageToLUMAWorkaroundTexture(context, texture, textureType, target, lumaFormat,
345                                                level, gl::Offset(0, 0, 0), sourceArea, source);
346 }
347 
copySubImageToLUMAWorkaroundTexture(const gl::Context * context,GLuint texture,gl::TextureType textureType,gl::TextureTarget target,GLenum lumaFormat,size_t level,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)348 angle::Result BlitGL::copySubImageToLUMAWorkaroundTexture(const gl::Context *context,
349                                                           GLuint texture,
350                                                           gl::TextureType textureType,
351                                                           gl::TextureTarget target,
352                                                           GLenum lumaFormat,
353                                                           size_t level,
354                                                           const gl::Offset &destOffset,
355                                                           const gl::Rectangle &sourceArea,
356                                                           gl::Framebuffer *source)
357 {
358     ANGLE_TRY(initializeResources(context));
359 
360     BlitProgram *blitProgram = nullptr;
361     ANGLE_TRY(getBlitProgram(context, gl::TextureType::_2D, GL_FLOAT, GL_FLOAT, &blitProgram));
362 
363     // Blit the framebuffer to the first scratch texture
364     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
365     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
366 
367     GLenum readFormat = source->getImplementationColorReadFormat(context);
368     GLenum readType   = source->getImplementationColorReadType(context);
369 
370     // getImplementationColorReadType aligns the type with ES client version
371     if (readType == GL_HALF_FLOAT_OES && mFunctions->standard == STANDARD_GL_DESKTOP)
372     {
373         readType = GL_HALF_FLOAT;
374     }
375 
376     nativegl::CopyTexImageImageFormat copyTexImageFormat =
377         nativegl::GetCopyTexImageImageFormat(mFunctions, mFeatures, readFormat, readType);
378 
379     mStateManager->bindTexture(gl::TextureType::_2D, mScratchTextures[0]);
380     ANGLE_GL_TRY_ALWAYS_CHECK(
381         context, mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, copyTexImageFormat.internalFormat,
382                                             sourceArea.x, sourceArea.y, sourceArea.width,
383                                             sourceArea.height, 0));
384 
385     // Set the swizzle of the scratch texture so that the channels sample into the correct emulated
386     // LUMA channels.
387     GLint swizzle[4] = {
388         (lumaFormat == GL_ALPHA) ? GL_ALPHA : GL_RED,
389         (lumaFormat == GL_LUMINANCE_ALPHA) ? GL_ALPHA : GL_ZERO,
390         GL_ZERO,
391         GL_ZERO,
392     };
393     ANGLE_GL_TRY(context,
394                  mFunctions->texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle));
395 
396     // Make a temporary framebuffer using the second scratch texture to render the swizzled result
397     // to.
398     mStateManager->bindTexture(gl::TextureType::_2D, mScratchTextures[1]);
399     ANGLE_GL_TRY_ALWAYS_CHECK(
400         context, mFunctions->texImage2D(GL_TEXTURE_2D, 0, copyTexImageFormat.internalFormat,
401                                         sourceArea.width, sourceArea.height, 0,
402                                         gl::GetUnsizedFormat(copyTexImageFormat.internalFormat),
403                                         readType, nullptr));
404 
405     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
406     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
407                                                            GL_TEXTURE_2D, mScratchTextures[1], 0));
408 
409     // Render to the destination texture, sampling from the scratch texture
410     ScopedGLState scopedState;
411     ANGLE_TRY(scopedState.enter(context, gl::Rectangle(0, 0, sourceArea.width, sourceArea.height)));
412     scopedState.willUseTextureUnit(context, 0);
413 
414     ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
415     ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
416 
417     mStateManager->activeTexture(0);
418     mStateManager->bindTexture(gl::TextureType::_2D, mScratchTextures[0]);
419 
420     mStateManager->useProgram(blitProgram->program);
421     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
422     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, 1.0, 1.0));
423     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->offsetLocation, 0.0, 0.0));
424     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
425     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
426     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->transformLinearToSrgbLocation, 0));
427 
428     ANGLE_TRY(setVAOState(context));
429     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
430 
431     // Copy the swizzled texture to the destination texture
432     mStateManager->bindTexture(textureType, texture);
433 
434     if (nativegl::UseTexImage3D(textureType))
435     {
436         ANGLE_GL_TRY(context,
437                      mFunctions->copyTexSubImage3D(ToGLenum(target), static_cast<GLint>(level),
438                                                    destOffset.x, destOffset.y, destOffset.z, 0, 0,
439                                                    sourceArea.width, sourceArea.height));
440     }
441     else
442     {
443         ASSERT(nativegl::UseTexImage2D(textureType));
444         ANGLE_GL_TRY(context, mFunctions->copyTexSubImage2D(
445                                   ToGLenum(target), static_cast<GLint>(level), destOffset.x,
446                                   destOffset.y, 0, 0, sourceArea.width, sourceArea.height));
447     }
448 
449     // Finally orphan the scratch textures so they can be GCed by the driver.
450     ANGLE_TRY(orphanScratchTextures(context));
451     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
452 
453     ANGLE_TRY(scopedState.exit(context));
454     return angle::Result::Continue;
455 }
456 
blitColorBufferWithShader(const gl::Context * context,const gl::Framebuffer * source,const GLuint destTexture,const gl::TextureTarget destTarget,const size_t destLevel,const gl::Rectangle & sourceAreaIn,const gl::Rectangle & destAreaIn,GLenum filter,bool writeAlpha)457 angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
458                                                 const gl::Framebuffer *source,
459                                                 const GLuint destTexture,
460                                                 const gl::TextureTarget destTarget,
461                                                 const size_t destLevel,
462                                                 const gl::Rectangle &sourceAreaIn,
463                                                 const gl::Rectangle &destAreaIn,
464                                                 GLenum filter,
465                                                 bool writeAlpha)
466 {
467     ANGLE_TRY(initializeResources(context));
468     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
469     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
470                                                            ToGLenum(destTarget), destTexture,
471                                                            static_cast<GLint>(destLevel)));
472     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
473     if (status != GL_FRAMEBUFFER_COMPLETE)
474     {
475         return angle::Result::Stop;
476     }
477     angle::Result result = blitColorBufferWithShader(context, source, mScratchFBO, sourceAreaIn,
478                                                      destAreaIn, filter, writeAlpha);
479     // Unbind the texture from the the scratch framebuffer.
480     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
481     return result;
482 }
483 
blitColorBufferWithShader(const gl::Context * context,const gl::Framebuffer * source,const gl::Framebuffer * dest,const gl::Rectangle & sourceAreaIn,const gl::Rectangle & destAreaIn,GLenum filter,bool writeAlpha)484 angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
485                                                 const gl::Framebuffer *source,
486                                                 const gl::Framebuffer *dest,
487                                                 const gl::Rectangle &sourceAreaIn,
488                                                 const gl::Rectangle &destAreaIn,
489                                                 GLenum filter,
490                                                 bool writeAlpha)
491 {
492     const FramebufferGL *destGL = GetImplAs<FramebufferGL>(dest);
493     return blitColorBufferWithShader(context, source, destGL->getFramebufferID(), sourceAreaIn,
494                                      destAreaIn, filter, writeAlpha);
495 }
496 
blitColorBufferWithShader(const gl::Context * context,const gl::Framebuffer * source,const GLuint destFramebuffer,const gl::Rectangle & sourceAreaIn,const gl::Rectangle & destAreaIn,GLenum filter,bool writeAlpha)497 angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
498                                                 const gl::Framebuffer *source,
499                                                 const GLuint destFramebuffer,
500                                                 const gl::Rectangle &sourceAreaIn,
501                                                 const gl::Rectangle &destAreaIn,
502                                                 GLenum filter,
503                                                 bool writeAlpha)
504 {
505     ANGLE_TRY(initializeResources(context));
506 
507     BlitProgram *blitProgram = nullptr;
508     ANGLE_TRY(getBlitProgram(context, gl::TextureType::_2D, GL_FLOAT, GL_FLOAT, &blitProgram));
509 
510     // We'll keep things simple by removing reversed coordinates from the rectangles. In the end
511     // we'll apply the reversal to the source texture coordinates if needed. The destination
512     // rectangle will be set to the gl viewport, which can't be reversed.
513     bool reverseX            = sourceAreaIn.isReversedX() != destAreaIn.isReversedX();
514     bool reverseY            = sourceAreaIn.isReversedY() != destAreaIn.isReversedY();
515     gl::Rectangle sourceArea = sourceAreaIn.removeReversal();
516     gl::Rectangle destArea   = destAreaIn.removeReversal();
517 
518     const gl::FramebufferAttachment *readAttachment = source->getReadColorAttachment();
519     ASSERT(readAttachment->getSamples() <= 1);
520 
521     // Compute the part of the source that will be sampled.
522     gl::Rectangle inBoundsSource;
523     {
524         gl::Extents sourceSize = readAttachment->getSize();
525         gl::Rectangle sourceBounds(0, 0, sourceSize.width, sourceSize.height);
526         if (!gl::ClipRectangle(sourceArea, sourceBounds, &inBoundsSource))
527         {
528             // Early out when the sampled part is empty as the blit will be a noop,
529             // and it prevents a division by zero in later computations.
530             return angle::Result::Continue;
531         }
532     }
533 
534     // The blit will be emulated by getting the source of the blit in a texture and sampling it
535     // with CLAMP_TO_EDGE.
536 
537     GLuint textureId;
538 
539     // TODO(cwallez) once texture dirty bits are landed, reuse attached texture instead of using
540     // CopyTexImage2D
541     {
542         textureId = mScratchTextures[0];
543 
544         const gl::InternalFormat &sourceInternalFormat       = *readAttachment->getFormat().info;
545         nativegl::CopyTexImageImageFormat copyTexImageFormat = nativegl::GetCopyTexImageImageFormat(
546             mFunctions, mFeatures, sourceInternalFormat.internalFormat, sourceInternalFormat.type);
547         const FramebufferGL *sourceGL = GetImplAs<FramebufferGL>(source);
548         mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceGL->getFramebufferID());
549         mStateManager->bindTexture(gl::TextureType::_2D, textureId);
550 
551         ANGLE_GL_TRY_ALWAYS_CHECK(
552             context, mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, copyTexImageFormat.internalFormat,
553                                                 inBoundsSource.x, inBoundsSource.y,
554                                                 inBoundsSource.width, inBoundsSource.height, 0));
555 
556         // Translate sourceArea to be relative to the copied image.
557         sourceArea.x -= inBoundsSource.x;
558         sourceArea.y -= inBoundsSource.y;
559 
560         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MIN_FILTER, filter));
561         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MAG_FILTER, filter));
562         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
563         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
564     }
565 
566     // Transform the source area to the texture coordinate space (where 0.0 and 1.0 correspond to
567     // the edges of the texture).
568     Vector2 texCoordOffset(
569         static_cast<float>(sourceArea.x) / static_cast<float>(inBoundsSource.width),
570         static_cast<float>(sourceArea.y) / static_cast<float>(inBoundsSource.height));
571     // texCoordScale is equal to the size of the source area in texture coordinates.
572     Vector2 texCoordScale(
573         static_cast<float>(sourceArea.width) / static_cast<float>(inBoundsSource.width),
574         static_cast<float>(sourceArea.height) / static_cast<float>(inBoundsSource.height));
575 
576     if (reverseX)
577     {
578         texCoordOffset.x() = texCoordOffset.x() + texCoordScale.x();
579         texCoordScale.x()  = -texCoordScale.x();
580     }
581     if (reverseY)
582     {
583         texCoordOffset.y() = texCoordOffset.y() + texCoordScale.y();
584         texCoordScale.y()  = -texCoordScale.y();
585     }
586 
587     // Reset all the state except scissor and use the viewport to draw exactly to the destination
588     // rectangle
589     ScopedGLState scopedState;
590     ANGLE_TRY(scopedState.enter(context, destArea, ScopedGLState::KEEP_SCISSOR));
591     scopedState.willUseTextureUnit(context, 0);
592 
593     // Set the write color mask to potentially not write alpha
594     mStateManager->setColorMask(true, true, true, writeAlpha);
595 
596     // Set uniforms
597     mStateManager->activeTexture(0);
598     mStateManager->bindTexture(gl::TextureType::_2D, textureId);
599 
600     mStateManager->useProgram(blitProgram->program);
601     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
602     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, texCoordScale.x(),
603                                                 texCoordScale.y()));
604     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->offsetLocation, texCoordOffset.x(),
605                                                 texCoordOffset.y()));
606     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
607     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
608     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->transformLinearToSrgbLocation, 0));
609 
610     mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, destFramebuffer);
611 
612     ANGLE_TRY(setVAOState(context));
613     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
614 
615     ANGLE_TRY(scopedState.exit(context));
616     return angle::Result::Continue;
617 }
618 
copySubTexture(const gl::Context * context,TextureGL * source,size_t sourceLevel,GLenum sourceComponentType,GLuint destID,gl::TextureTarget destTarget,size_t destLevel,GLenum destComponentType,const gl::Extents & sourceSize,const gl::Rectangle & sourceArea,const gl::Offset & destOffset,bool needsLumaWorkaround,GLenum lumaFormat,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,bool transformLinearToSrgb,bool * copySucceededOut)619 angle::Result BlitGL::copySubTexture(const gl::Context *context,
620                                      TextureGL *source,
621                                      size_t sourceLevel,
622                                      GLenum sourceComponentType,
623                                      GLuint destID,
624                                      gl::TextureTarget destTarget,
625                                      size_t destLevel,
626                                      GLenum destComponentType,
627                                      const gl::Extents &sourceSize,
628                                      const gl::Rectangle &sourceArea,
629                                      const gl::Offset &destOffset,
630                                      bool needsLumaWorkaround,
631                                      GLenum lumaFormat,
632                                      bool unpackFlipY,
633                                      bool unpackPremultiplyAlpha,
634                                      bool unpackUnmultiplyAlpha,
635                                      bool transformLinearToSrgb,
636                                      bool *copySucceededOut)
637 {
638     ASSERT(source->getType() == gl::TextureType::_2D ||
639            source->getType() == gl::TextureType::External ||
640            source->getType() == gl::TextureType::Rectangle);
641     ANGLE_TRY(initializeResources(context));
642 
643     // Make sure the destination texture can be rendered to before setting anything else up.  Some
644     // cube maps may not be renderable until all faces have been filled.
645     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
646     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
647                                                            ToGLenum(destTarget), destID,
648                                                            static_cast<GLint>(destLevel)));
649     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
650     if (status != GL_FRAMEBUFFER_COMPLETE)
651     {
652         *copySucceededOut = false;
653         return angle::Result::Continue;
654     }
655 
656     BlitProgram *blitProgram = nullptr;
657     ANGLE_TRY(getBlitProgram(context, source->getType(), sourceComponentType, destComponentType,
658                              &blitProgram));
659 
660     // Setup the source texture
661     if (needsLumaWorkaround)
662     {
663         GLint luminance = (lumaFormat == GL_ALPHA) ? GL_ZERO : GL_RED;
664 
665         GLint alpha = GL_RED;
666         if (lumaFormat == GL_LUMINANCE)
667         {
668             alpha = GL_ONE;
669         }
670         else if (lumaFormat == GL_LUMINANCE_ALPHA)
671         {
672             alpha = GL_GREEN;
673         }
674         else
675         {
676             ASSERT(lumaFormat == GL_ALPHA);
677         }
678 
679         GLint swizzle[4] = {luminance, luminance, luminance, alpha};
680         ANGLE_TRY(source->setSwizzle(context, swizzle));
681     }
682     ANGLE_TRY(source->setMinFilter(context, GL_NEAREST));
683     ANGLE_TRY(source->setMagFilter(context, GL_NEAREST));
684     ANGLE_TRY(source->setBaseLevel(context, static_cast<GLuint>(sourceLevel)));
685 
686     // Render to the destination texture, sampling from the source texture
687     ScopedGLState scopedState;
688     ANGLE_TRY(scopedState.enter(
689         context, gl::Rectangle(destOffset.x, destOffset.y, sourceArea.width, sourceArea.height)));
690     scopedState.willUseTextureUnit(context, 0);
691 
692     mStateManager->activeTexture(0);
693     mStateManager->bindTexture(source->getType(), source->getTextureID());
694 
695     Vector2 scale(sourceArea.width, sourceArea.height);
696     Vector2 offset(sourceArea.x, sourceArea.y);
697     if (source->getType() != gl::TextureType::Rectangle)
698     {
699         scale.x() /= static_cast<float>(sourceSize.width);
700         scale.y() /= static_cast<float>(sourceSize.height);
701         offset.x() /= static_cast<float>(sourceSize.width);
702         offset.y() /= static_cast<float>(sourceSize.height);
703     }
704     if (unpackFlipY)
705     {
706         offset.y() += scale.y();
707         scale.y() = -scale.y();
708     }
709 
710     mStateManager->useProgram(blitProgram->program);
711     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
712     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, scale.x(), scale.y()));
713     ANGLE_GL_TRY(context,
714                  mFunctions->uniform2f(blitProgram->offsetLocation, offset.x(), offset.y()));
715     if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha)
716     {
717         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
718         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
719     }
720     else
721     {
722         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation,
723                                                     unpackPremultiplyAlpha));
724         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation,
725                                                     unpackUnmultiplyAlpha));
726     }
727     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->transformLinearToSrgbLocation,
728                                                 transformLinearToSrgb));
729 
730     ANGLE_TRY(setVAOState(context));
731     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
732     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
733 
734     *copySucceededOut = true;
735     ANGLE_TRY(scopedState.exit(context));
736     return angle::Result::Continue;
737 }
738 
copySubTextureCPUReadback(const gl::Context * context,TextureGL * source,size_t sourceLevel,GLenum sourceSizedInternalFormat,TextureGL * dest,gl::TextureTarget destTarget,size_t destLevel,GLenum destFormat,GLenum destType,const gl::Extents & sourceSize,const gl::Rectangle & sourceArea,const gl::Offset & destOffset,bool needsLumaWorkaround,GLenum lumaFormat,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha)739 angle::Result BlitGL::copySubTextureCPUReadback(const gl::Context *context,
740                                                 TextureGL *source,
741                                                 size_t sourceLevel,
742                                                 GLenum sourceSizedInternalFormat,
743                                                 TextureGL *dest,
744                                                 gl::TextureTarget destTarget,
745                                                 size_t destLevel,
746                                                 GLenum destFormat,
747                                                 GLenum destType,
748                                                 const gl::Extents &sourceSize,
749                                                 const gl::Rectangle &sourceArea,
750                                                 const gl::Offset &destOffset,
751                                                 bool needsLumaWorkaround,
752                                                 GLenum lumaFormat,
753                                                 bool unpackFlipY,
754                                                 bool unpackPremultiplyAlpha,
755                                                 bool unpackUnmultiplyAlpha)
756 {
757     ANGLE_TRY(initializeResources(context));
758 
759     ContextGL *contextGL = GetImplAs<ContextGL>(context);
760 
761     ASSERT(source->getType() == gl::TextureType::_2D ||
762            source->getType() == gl::TextureType::External ||
763            source->getType() == gl::TextureType::Rectangle);
764     const auto &destInternalFormatInfo = gl::GetInternalFormatInfo(destFormat, destType);
765     const gl::InternalFormat &sourceInternalFormatInfo =
766         gl::GetSizedInternalFormatInfo(sourceSizedInternalFormat);
767 
768     gl::Rectangle readPixelsArea = sourceArea;
769 
770     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
771     bool supportExternalTarget =
772         source->getType() == gl::TextureType::External && context->getExtensions().YUVTargetEXT;
773     GLenum status = GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
774     if (supportExternalTarget || source->getType() != gl::TextureType::External)
775     {
776         ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
777                                   GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(source->getType()),
778                                   source->getTextureID(), static_cast<GLint>(sourceLevel)));
779         status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
780     }
781     if (status != GL_FRAMEBUFFER_COMPLETE)
782     {
783         // The source texture cannot be read with glReadPixels. Copy it into another RGBA texture
784         // and read that back instead.
785         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
786             mFunctions, mFeatures, sourceInternalFormatInfo.internalFormat,
787             sourceInternalFormatInfo.format, sourceInternalFormatInfo.type);
788 
789         gl::TextureType scratchTextureType = gl::TextureType::_2D;
790         mStateManager->bindTexture(scratchTextureType, mScratchTextures[0]);
791         ANGLE_GL_TRY_ALWAYS_CHECK(
792             context,
793             mFunctions->texImage2D(ToGLenum(scratchTextureType), 0, texImageFormat.internalFormat,
794                                    sourceArea.width, sourceArea.height, 0, texImageFormat.format,
795                                    texImageFormat.type, nullptr));
796 
797         bool copySucceeded = false;
798         ANGLE_TRY(copySubTexture(
799             context, source, sourceLevel, sourceInternalFormatInfo.componentType,
800             mScratchTextures[0], NonCubeTextureTypeToTarget(scratchTextureType), 0,
801             sourceInternalFormatInfo.componentType, sourceSize, sourceArea, gl::Offset(0, 0, 0),
802             needsLumaWorkaround, lumaFormat, false, false, false, false, &copySucceeded));
803         if (!copySucceeded)
804         {
805             // No fallback options if we can't render to the scratch texture.
806             return angle::Result::Stop;
807         }
808 
809         // Bind the scratch texture as the readback texture
810         mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
811         ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
812                                                                ToGLenum(scratchTextureType),
813                                                                mScratchTextures[0], 0));
814 
815         // The scratch texture sized to sourceArea so adjust the readpixels area
816         readPixelsArea.x = 0;
817         readPixelsArea.y = 0;
818 
819         // Recheck the status
820         status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
821     }
822 
823     ASSERT(status == GL_FRAMEBUFFER_COMPLETE);
824 
825     // Create a buffer for holding the source and destination memory
826     const size_t sourcePixelSize = 4;
827     size_t sourceBufferSize      = readPixelsArea.width * readPixelsArea.height * sourcePixelSize;
828     size_t destBufferSize =
829         readPixelsArea.width * readPixelsArea.height * destInternalFormatInfo.pixelBytes;
830     angle::MemoryBuffer *buffer = nullptr;
831     ANGLE_CHECK_GL_ALLOC(contextGL,
832                          context->getScratchBuffer(sourceBufferSize + destBufferSize, &buffer));
833 
834     uint8_t *sourceMemory = buffer->data();
835     uint8_t *destMemory   = buffer->data() + sourceBufferSize;
836 
837     GLenum readPixelsFormat        = GL_NONE;
838     PixelReadFunction readFunction = nullptr;
839     if (sourceInternalFormatInfo.componentType == GL_UNSIGNED_INT)
840     {
841         readPixelsFormat = GL_RGBA_INTEGER;
842         readFunction     = angle::ReadColor<angle::R8G8B8A8, GLuint>;
843     }
844     else
845     {
846         ASSERT(sourceInternalFormatInfo.componentType != GL_INT);
847         readPixelsFormat = GL_RGBA;
848         readFunction     = angle::ReadColor<angle::R8G8B8A8, GLfloat>;
849     }
850 
851     gl::PixelUnpackState unpack;
852     unpack.alignment = 1;
853     ANGLE_TRY(mStateManager->setPixelUnpackState(context, unpack));
854     ANGLE_TRY(mStateManager->setPixelUnpackBuffer(context, nullptr));
855     ANGLE_GL_TRY(context, mFunctions->readPixels(readPixelsArea.x, readPixelsArea.y,
856                                                  readPixelsArea.width, readPixelsArea.height,
857                                                  readPixelsFormat, GL_UNSIGNED_BYTE, sourceMemory));
858 
859     angle::FormatID destFormatID =
860         angle::Format::InternalFormatToID(destInternalFormatInfo.sizedInternalFormat);
861     const auto &destFormatInfo = angle::Format::Get(destFormatID);
862     CopyImageCHROMIUM(
863         sourceMemory, readPixelsArea.width * sourcePixelSize, sourcePixelSize, 0, readFunction,
864         destMemory, readPixelsArea.width * destInternalFormatInfo.pixelBytes,
865         destInternalFormatInfo.pixelBytes, 0, destFormatInfo.pixelWriteFunction,
866         destInternalFormatInfo.format, destInternalFormatInfo.componentType, readPixelsArea.width,
867         readPixelsArea.height, 1, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
868 
869     gl::PixelPackState pack;
870     pack.alignment = 1;
871     ANGLE_TRY(mStateManager->setPixelPackState(context, pack));
872     ANGLE_TRY(mStateManager->setPixelPackBuffer(context, nullptr));
873 
874     nativegl::TexSubImageFormat texSubImageFormat =
875         nativegl::GetTexSubImageFormat(mFunctions, mFeatures, destFormat, destType);
876 
877     mStateManager->bindTexture(dest->getType(), dest->getTextureID());
878     ANGLE_GL_TRY(context, mFunctions->texSubImage2D(
879                               ToGLenum(destTarget), static_cast<GLint>(destLevel), destOffset.x,
880                               destOffset.y, readPixelsArea.width, readPixelsArea.height,
881                               texSubImageFormat.format, texSubImageFormat.type, destMemory));
882 
883     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
884 
885     return angle::Result::Continue;
886 }
887 
copyTexSubImage(const gl::Context * context,TextureGL * source,size_t sourceLevel,TextureGL * dest,gl::TextureTarget destTarget,size_t destLevel,const gl::Rectangle & sourceArea,const gl::Offset & destOffset,bool * copySucceededOut)888 angle::Result BlitGL::copyTexSubImage(const gl::Context *context,
889                                       TextureGL *source,
890                                       size_t sourceLevel,
891                                       TextureGL *dest,
892                                       gl::TextureTarget destTarget,
893                                       size_t destLevel,
894                                       const gl::Rectangle &sourceArea,
895                                       const gl::Offset &destOffset,
896                                       bool *copySucceededOut)
897 {
898     ANGLE_TRY(initializeResources(context));
899 
900     // Make sure the source texture can create a complete framebuffer before continuing.
901     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
902     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
903                               GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(source->getType()),
904                               source->getTextureID(), static_cast<GLint>(sourceLevel)));
905     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
906     if (status != GL_FRAMEBUFFER_COMPLETE)
907     {
908         *copySucceededOut = false;
909         return angle::Result::Continue;
910     }
911 
912     mStateManager->bindTexture(dest->getType(), dest->getTextureID());
913 
914     // Handle GL errors during copyTexSubImage2D manually since this can fail for certain formats on
915     // Pixel 2 and 4 and we have fallback paths (blit via shader) in the caller.
916     ClearErrors(context, __FILE__, __FUNCTION__, __LINE__);
917     mFunctions->copyTexSubImage2D(ToGLenum(destTarget), static_cast<GLint>(destLevel), destOffset.x,
918                                   destOffset.y, sourceArea.x, sourceArea.y, sourceArea.width,
919                                   sourceArea.height);
920     // Use getError to retrieve the error directly instead of using CheckError so that we don't
921     // propagate the error to the client and also so that we can handle INVALID_OPERATION specially.
922     const GLenum copyError = mFunctions->getError();
923     // Any error other than NO_ERROR or INVALID_OPERATION is propagated to the client as a failure.
924     // INVALID_OPERATION is ignored and instead copySucceeded is set to false so that the caller can
925     // fallback to another copy/blit implementation.
926     if (ANGLE_UNLIKELY(copyError != GL_NO_ERROR && copyError != GL_INVALID_OPERATION))
927     {
928         // Propagate the error to the client and check for other unexpected errors.
929         ANGLE_TRY(
930             HandleError(context, copyError, "copyTexSubImage2D", __FILE__, __FUNCTION__, __LINE__));
931     }
932     // Even if copyTexSubImage2D fails with GL_INVALID_OPERATION, check for other unexpected errors.
933     ANGLE_TRY(CheckError(context, "copyTexSubImage2D", __FILE__, __FUNCTION__, __LINE__));
934 
935     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
936     *copySucceededOut = copyError == GL_NO_ERROR;
937     return angle::Result::Continue;
938 }
939 
clearRenderableTexture(const gl::Context * context,TextureGL * source,GLenum sizedInternalFormat,int numTextureLayers,const gl::ImageIndex & imageIndex,bool * clearSucceededOut)940 angle::Result BlitGL::clearRenderableTexture(const gl::Context *context,
941                                              TextureGL *source,
942                                              GLenum sizedInternalFormat,
943                                              int numTextureLayers,
944                                              const gl::ImageIndex &imageIndex,
945                                              bool *clearSucceededOut)
946 {
947     ANGLE_TRY(initializeResources(context));
948 
949     ClearBindTargetVector bindTargets;
950     ClearBindTargetVector unbindTargets;
951     GLbitfield clearMask = 0;
952     ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &unbindTargets,
953                               &clearMask));
954 
955     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
956     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, unbindTargets));
957 
958     if (nativegl::UseTexImage2D(source->getType()))
959     {
960         ASSERT(numTextureLayers == 1);
961         for (GLenum bindTarget : bindTargets)
962         {
963             ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
964                                       GL_FRAMEBUFFER, bindTarget, ToGLenum(imageIndex.getTarget()),
965                                       source->getTextureID(), imageIndex.getLevelIndex()));
966         }
967 
968         GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
969         if (status == GL_FRAMEBUFFER_COMPLETE)
970         {
971             ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
972         }
973         else
974         {
975             ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
976             *clearSucceededOut = false;
977             return angle::Result::Continue;
978         }
979     }
980     else
981     {
982         ASSERT(nativegl::UseTexImage3D(source->getType()));
983 
984         // Check if it's possible to bind all layers of the texture at once
985         if (mFunctions->framebufferTexture && !imageIndex.hasLayer())
986         {
987             for (GLenum bindTarget : bindTargets)
988             {
989                 ANGLE_GL_TRY(context, mFunctions->framebufferTexture(GL_FRAMEBUFFER, bindTarget,
990                                                                      source->getTextureID(),
991                                                                      imageIndex.getLevelIndex()));
992             }
993 
994             GLenum status =
995                 ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
996             if (status == GL_FRAMEBUFFER_COMPLETE)
997             {
998                 ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
999             }
1000             else
1001             {
1002                 ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
1003                 *clearSucceededOut = false;
1004                 return angle::Result::Continue;
1005             }
1006         }
1007         else
1008         {
1009             GLint firstLayer = 0;
1010             GLint layerCount = numTextureLayers;
1011             if (imageIndex.hasLayer())
1012             {
1013                 firstLayer = imageIndex.getLayerIndex();
1014                 layerCount = imageIndex.getLayerCount();
1015             }
1016 
1017             for (GLint layer = 0; layer < layerCount; layer++)
1018             {
1019                 for (GLenum bindTarget : bindTargets)
1020                 {
1021                     ANGLE_GL_TRY(context, mFunctions->framebufferTextureLayer(
1022                                               GL_FRAMEBUFFER, bindTarget, source->getTextureID(),
1023                                               imageIndex.getLevelIndex(), layer + firstLayer));
1024                 }
1025 
1026                 GLenum status =
1027                     ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
1028                 if (status == GL_FRAMEBUFFER_COMPLETE)
1029                 {
1030                     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
1031                 }
1032                 else
1033                 {
1034                     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
1035                     *clearSucceededOut = false;
1036                     return angle::Result::Continue;
1037                 }
1038             }
1039         }
1040     }
1041 
1042     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
1043     *clearSucceededOut = true;
1044     return angle::Result::Continue;
1045 }
1046 
clearRenderbuffer(const gl::Context * context,RenderbufferGL * source,GLenum sizedInternalFormat)1047 angle::Result BlitGL::clearRenderbuffer(const gl::Context *context,
1048                                         RenderbufferGL *source,
1049                                         GLenum sizedInternalFormat)
1050 {
1051     ANGLE_TRY(initializeResources(context));
1052 
1053     ClearBindTargetVector bindTargets;
1054     ClearBindTargetVector unbindTargets;
1055     GLbitfield clearMask = 0;
1056     ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &unbindTargets,
1057                               &clearMask));
1058 
1059     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
1060     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, unbindTargets));
1061 
1062     for (GLenum bindTarget : bindTargets)
1063     {
1064         ANGLE_GL_TRY(context,
1065                      mFunctions->framebufferRenderbuffer(
1066                          GL_FRAMEBUFFER, bindTarget, GL_RENDERBUFFER, source->getRenderbufferID()));
1067     }
1068     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
1069 
1070     // Unbind
1071     for (GLenum bindTarget : bindTargets)
1072     {
1073         ANGLE_GL_TRY(context, mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, bindTarget,
1074                                                                   GL_RENDERBUFFER, 0));
1075     }
1076 
1077     return angle::Result::Continue;
1078 }
1079 
clearFramebuffer(const gl::Context * context,const gl::DrawBufferMask & colorAttachments,bool depthClear,bool stencilClear,FramebufferGL * source)1080 angle::Result BlitGL::clearFramebuffer(const gl::Context *context,
1081                                        const gl::DrawBufferMask &colorAttachments,
1082                                        bool depthClear,
1083                                        bool stencilClear,
1084                                        FramebufferGL *source)
1085 {
1086     // initializeResources skipped because no local state is used
1087 
1088     bool hasIntegerColorAttachments = false;
1089 
1090     // Filter the color attachments for ones that actually have an init state of uninitialized.
1091     gl::DrawBufferMask uninitializedColorAttachments;
1092     for (size_t colorAttachmentIdx : colorAttachments)
1093     {
1094         bool needsInit = false;
1095         const gl::FramebufferAttachment *attachment =
1096             source->getState().getColorAttachment(colorAttachmentIdx);
1097         ANGLE_TRY(CheckIfAttachmentNeedsClearing(context, attachment, &needsInit));
1098         uninitializedColorAttachments[colorAttachmentIdx] = needsInit;
1099         if (needsInit && (attachment->getComponentType() == GL_INT ||
1100                           attachment->getComponentType() == GL_UNSIGNED_INT))
1101         {
1102             hasIntegerColorAttachments = true;
1103         }
1104     }
1105 
1106     bool depthNeedsInit = false;
1107     if (depthClear)
1108     {
1109         ANGLE_TRY(CheckIfAttachmentNeedsClearing(context, source->getState().getDepthAttachment(),
1110                                                  &depthNeedsInit));
1111     }
1112 
1113     bool stencilNeedsInit = false;
1114     if (stencilClear)
1115     {
1116         ANGLE_TRY(CheckIfAttachmentNeedsClearing(context, source->getState().getStencilAttachment(),
1117                                                  &stencilNeedsInit));
1118     }
1119 
1120     // Clear all attachments
1121     GLbitfield clearMask = 0;
1122     ANGLE_TRY(SetClearState(mStateManager, uninitializedColorAttachments.any(), depthNeedsInit,
1123                             stencilNeedsInit, &clearMask));
1124 
1125     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, source->getFramebufferID());
1126 
1127     // If we're not clearing all attached color attachments, we need to clear them individually with
1128     // glClearBuffer*
1129     if ((clearMask & GL_COLOR_BUFFER_BIT) &&
1130         (uninitializedColorAttachments != source->getState().getColorAttachmentsMask() ||
1131          uninitializedColorAttachments != source->getState().getEnabledDrawBuffers() ||
1132          hasIntegerColorAttachments))
1133     {
1134         for (size_t colorAttachmentIdx : uninitializedColorAttachments)
1135         {
1136             const gl::FramebufferAttachment *attachment =
1137                 source->getState().getColorAttachment(colorAttachmentIdx);
1138             if (attachment->initState() == gl::InitState::Initialized)
1139             {
1140                 continue;
1141             }
1142 
1143             switch (attachment->getComponentType())
1144             {
1145                 case GL_UNSIGNED_NORMALIZED:
1146                 case GL_SIGNED_NORMALIZED:
1147                 case GL_FLOAT:
1148                 {
1149                     constexpr GLfloat clearValue[] = {0, 0, 0, 0};
1150                     ANGLE_GL_TRY(context,
1151                                  mFunctions->clearBufferfv(
1152                                      GL_COLOR, static_cast<GLint>(colorAttachmentIdx), clearValue));
1153                 }
1154                 break;
1155 
1156                 case GL_INT:
1157                 {
1158                     constexpr GLint clearValue[] = {0, 0, 0, 0};
1159                     ANGLE_GL_TRY(context,
1160                                  mFunctions->clearBufferiv(
1161                                      GL_COLOR, static_cast<GLint>(colorAttachmentIdx), clearValue));
1162                 }
1163                 break;
1164 
1165                 case GL_UNSIGNED_INT:
1166                 {
1167                     constexpr GLuint clearValue[] = {0, 0, 0, 0};
1168                     ANGLE_GL_TRY(context,
1169                                  mFunctions->clearBufferuiv(
1170                                      GL_COLOR, static_cast<GLint>(colorAttachmentIdx), clearValue));
1171                 }
1172                 break;
1173 
1174                 default:
1175                     UNREACHABLE();
1176                     break;
1177             }
1178         }
1179 
1180         // Remove color buffer bit and clear the rest of the attachments with glClear
1181         clearMask = clearMask & ~GL_COLOR_BUFFER_BIT;
1182     }
1183 
1184     if (clearMask != 0)
1185     {
1186         ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
1187     }
1188 
1189     return angle::Result::Continue;
1190 }
1191 
clearRenderableTextureAlphaToOne(const gl::Context * context,GLuint texture,gl::TextureTarget target,size_t level)1192 angle::Result BlitGL::clearRenderableTextureAlphaToOne(const gl::Context *context,
1193                                                        GLuint texture,
1194                                                        gl::TextureTarget target,
1195                                                        size_t level)
1196 {
1197     // Clearing the alpha of 3D textures is not supported/needed yet.
1198     ASSERT(nativegl::UseTexImage2D(TextureTargetToType(target)));
1199 
1200     ANGLE_TRY(initializeResources(context));
1201 
1202     mStateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
1203     mStateManager->setColorMask(false, false, false, true);
1204     mStateManager->setScissorTestEnabled(false);
1205 
1206     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
1207     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1208                                                            ToGLenum(target), texture,
1209                                                            static_cast<GLint>(level)));
1210     ANGLE_GL_TRY(context, mFunctions->clear(GL_COLOR_BUFFER_BIT));
1211 
1212     // Unbind the texture from the the scratch framebuffer
1213     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
1214 
1215     return angle::Result::Continue;
1216 }
1217 
generateMipmap(const gl::Context * context,TextureGL * source,GLuint baseLevel,GLuint levelCount,const gl::Extents & sourceBaseLevelSize,const nativegl::TexImageFormat & format)1218 angle::Result BlitGL::generateMipmap(const gl::Context *context,
1219                                      TextureGL *source,
1220                                      GLuint baseLevel,
1221                                      GLuint levelCount,
1222                                      const gl::Extents &sourceBaseLevelSize,
1223                                      const nativegl::TexImageFormat &format)
1224 {
1225     ANGLE_TRY(initializeResources(context));
1226 
1227     const gl::TextureType sourceType     = gl::TextureType::_2D;
1228     const gl::TextureTarget sourceTarget = gl::TextureTarget::_2D;
1229 
1230     ScopedGLState scopedState;
1231     ANGLE_TRY(scopedState.enter(
1232         context, gl::Rectangle(0, 0, sourceBaseLevelSize.width, sourceBaseLevelSize.height)));
1233     scopedState.willUseTextureUnit(context, 0);
1234     mStateManager->activeTexture(0);
1235 
1236     // Copy source to an intermediate texture.
1237     GLuint intermediateTexture = mScratchTextures[0];
1238     mStateManager->bindTexture(sourceType, intermediateTexture);
1239     mStateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1240     ANGLE_GL_TRY(context, mFunctions->texParameteri(ToGLenum(sourceTarget), GL_TEXTURE_MIN_FILTER,
1241                                                     GL_NEAREST));
1242     ANGLE_GL_TRY(context, mFunctions->texParameteri(ToGLenum(sourceTarget), GL_TEXTURE_MAG_FILTER,
1243                                                     GL_NEAREST));
1244 
1245     // Use a shader to copy the source to intermediate texture. glBlitFramebuffer does not always do
1246     // sRGB to linear conversions for us.
1247     BlitProgram *blitProgram = nullptr;
1248     ANGLE_TRY(getBlitProgram(context, sourceType, GL_FLOAT, GL_FLOAT, &blitProgram));
1249 
1250     mStateManager->useProgram(blitProgram->program);
1251     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
1252     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, 1.0f, 1.0f));
1253     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->offsetLocation, 0.0f, 0.0f));
1254     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
1255     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
1256     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->transformLinearToSrgbLocation, 0));
1257 
1258     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
1259     mStateManager->setFramebufferSRGBEnabled(context, true);
1260 
1261     ANGLE_TRY(setVAOState(context));
1262 
1263     ANGLE_TRY(source->setMinFilter(context, GL_LINEAR));
1264     ANGLE_TRY(source->setMagFilter(context, GL_LINEAR));
1265 
1266     // Copy back to the source texture from the mips generated in the intermediate texture
1267     for (GLuint levelIdx = 1; levelIdx < levelCount; levelIdx++)
1268     {
1269         gl::Extents levelSize(std::max(sourceBaseLevelSize.width >> levelIdx, 1),
1270                               std::max(sourceBaseLevelSize.height >> levelIdx, 1), 1);
1271 
1272         // Downsample from the source texture into the intermediate texture
1273         mStateManager->bindTexture(sourceType, intermediateTexture);
1274         ANGLE_GL_TRY(context, mFunctions->texImage2D(
1275                                   ToGLenum(sourceTarget), 0, format.internalFormat, levelSize.width,
1276                                   levelSize.height, 0, format.format, format.type, nullptr));
1277 
1278         ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1279                                                                ToGLenum(sourceTarget),
1280                                                                intermediateTexture, 0));
1281         mStateManager->setViewport(gl::Rectangle(0, 0, levelSize.width, levelSize.height));
1282 
1283         GLuint sourceTextureReadLevel = baseLevel + levelIdx - 1;
1284         mStateManager->bindTexture(sourceType, source->getTextureID());
1285         ANGLE_TRY(source->setBaseLevel(context, sourceTextureReadLevel));
1286         ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
1287 
1288         // Copy back to the source texture
1289         GLuint sourceTextureWriteLevel = sourceTextureReadLevel + 1;
1290         ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
1291                                   GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(sourceTarget),
1292                                   source->getTextureID(), sourceTextureWriteLevel));
1293         mStateManager->bindTexture(sourceType, intermediateTexture);
1294         ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
1295     }
1296 
1297     ANGLE_TRY(source->setBaseLevel(context, baseLevel));
1298 
1299     ANGLE_TRY(orphanScratchTextures(context));
1300     ANGLE_TRY(UnbindAttachment(context, mFunctions, GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0));
1301 
1302     ANGLE_TRY(scopedState.exit(context));
1303     return angle::Result::Continue;
1304 }
1305 
generateSRGBMipmap(const gl::Context * context,TextureGL * source,GLuint baseLevel,GLuint levelCount,const gl::Extents & sourceBaseLevelSize)1306 angle::Result BlitGL::generateSRGBMipmap(const gl::Context *context,
1307                                          TextureGL *source,
1308                                          GLuint baseLevel,
1309                                          GLuint levelCount,
1310                                          const gl::Extents &sourceBaseLevelSize)
1311 {
1312     return generateMipmap(context, source, baseLevel, levelCount, sourceBaseLevelSize,
1313                           mSRGBMipmapGenerationFormat);
1314 }
1315 
initializeResources(const gl::Context * context)1316 angle::Result BlitGL::initializeResources(const gl::Context *context)
1317 {
1318     if (mResourcesInitialized)
1319     {
1320         return angle::Result::Continue;
1321     }
1322 
1323     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
1324     {
1325         ANGLE_GL_TRY(context, mFunctions->genTextures(1, &mScratchTextures[i]));
1326     }
1327 
1328     ANGLE_GL_TRY(context, mFunctions->genFramebuffers(1, &mScratchFBO));
1329 
1330     ANGLE_GL_TRY(context, mFunctions->genBuffers(1, &mVertexBuffer));
1331     mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
1332 
1333     // Use a single, large triangle, to avoid arithmetic precision issues where fragments
1334     // with the same Y coordinate don't get exactly the same interpolated texcoord Y.
1335     float vertexData[] = {
1336         -0.5f, 0.0f, 1.5f, 0.0f, 0.5f, 2.0f,
1337     };
1338 
1339     ANGLE_GL_TRY(context, mFunctions->bufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, vertexData,
1340                                                  GL_STATIC_DRAW));
1341 
1342     VertexArrayStateGL *defaultVAOState = mStateManager->getDefaultVAOState();
1343     if (!mFeatures.syncAllVertexArraysToDefault.enabled)
1344     {
1345         ANGLE_GL_TRY(context, mFunctions->genVertexArrays(1, &mVAO));
1346         mVAOState     = new VertexArrayStateGL(defaultVAOState->attributes.size(),
1347                                                defaultVAOState->bindings.size());
1348         mOwnsVAOState = true;
1349         ANGLE_TRY(setVAOState(context));
1350         ANGLE_TRY(initializeVAOState(context));
1351     }
1352     else
1353     {
1354         mVAO          = mStateManager->getDefaultVAO();
1355         mVAOState     = defaultVAOState;
1356         mOwnsVAOState = false;
1357     }
1358 
1359     constexpr GLenum potentialSRGBMipmapGenerationFormats[] = {
1360         GL_RGBA16, GL_RGBA16F, GL_RGBA32F,
1361         GL_RGBA8,  // RGBA8 can have precision loss when generating mipmaps of a sRGBA8 texture
1362     };
1363     for (GLenum internalFormat : potentialSRGBMipmapGenerationFormats)
1364     {
1365         if (nativegl::SupportsNativeRendering(mFunctions, gl::TextureType::_2D, internalFormat))
1366         {
1367             const gl::InternalFormat &internalFormatInfo =
1368                 gl::GetSizedInternalFormatInfo(internalFormat);
1369 
1370             // Pass the 'format' instead of 'internalFormat' to make sure we use unsized formats
1371             // when available to increase support.
1372             mSRGBMipmapGenerationFormat =
1373                 nativegl::GetTexImageFormat(mFunctions, mFeatures, internalFormatInfo.format,
1374                                             internalFormatInfo.format, internalFormatInfo.type);
1375             break;
1376         }
1377     }
1378     ASSERT(mSRGBMipmapGenerationFormat.internalFormat != GL_NONE);
1379 
1380     mResourcesInitialized = true;
1381     return angle::Result::Continue;
1382 }
1383 
orphanScratchTextures(const gl::Context * context)1384 angle::Result BlitGL::orphanScratchTextures(const gl::Context *context)
1385 {
1386     for (auto texture : mScratchTextures)
1387     {
1388         mStateManager->bindTexture(gl::TextureType::_2D, texture);
1389         gl::PixelUnpackState unpack;
1390         ANGLE_TRY(mStateManager->setPixelUnpackState(context, unpack));
1391         ANGLE_TRY(mStateManager->setPixelUnpackBuffer(context, nullptr));
1392         if (mFunctions->isAtLeastGL(gl::Version(3, 3)))
1393         {
1394             constexpr GLint swizzle[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
1395             ANGLE_GL_TRY(context, mFunctions->texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA,
1396                                                              swizzle));
1397         }
1398         else if (mFunctions->isAtLeastGLES(gl::Version(3, 0)))
1399         {
1400             ANGLE_GL_TRY(context,
1401                          mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED));
1402             ANGLE_GL_TRY(context,
1403                          mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN));
1404             ANGLE_GL_TRY(context,
1405                          mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE));
1406             ANGLE_GL_TRY(context,
1407                          mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA));
1408         }
1409 
1410         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0));
1411         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1000));
1412         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
1413                                                         GL_NEAREST_MIPMAP_LINEAR));
1414         ANGLE_GL_TRY(context,
1415                      mFunctions->texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
1416         ANGLE_GL_TRY(context, mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
1417                                                      GL_UNSIGNED_BYTE, nullptr));
1418     }
1419 
1420     return angle::Result::Continue;
1421 }
1422 
setScratchTextureParameter(const gl::Context * context,GLenum param,GLenum value)1423 angle::Result BlitGL::setScratchTextureParameter(const gl::Context *context,
1424                                                  GLenum param,
1425                                                  GLenum value)
1426 {
1427     for (auto texture : mScratchTextures)
1428     {
1429         mStateManager->bindTexture(gl::TextureType::_2D, texture);
1430         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, param, value));
1431         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, param, value));
1432     }
1433     return angle::Result::Continue;
1434 }
1435 
setVAOState(const gl::Context * context)1436 angle::Result BlitGL::setVAOState(const gl::Context *context)
1437 {
1438     mStateManager->bindVertexArray(mVAO, mVAOState);
1439     if (mFeatures.syncAllVertexArraysToDefault.enabled)
1440     {
1441         ANGLE_TRY(initializeVAOState(context));
1442     }
1443 
1444     return angle::Result::Continue;
1445 }
1446 
initializeVAOState(const gl::Context * context)1447 angle::Result BlitGL::initializeVAOState(const gl::Context *context)
1448 {
1449     mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
1450 
1451     ANGLE_GL_TRY(context, mFunctions->enableVertexAttribArray(mTexcoordAttribLocation));
1452     ANGLE_GL_TRY(context, mFunctions->vertexAttribPointer(mTexcoordAttribLocation, 2, GL_FLOAT,
1453                                                           GL_FALSE, 0, nullptr));
1454 
1455     VertexAttributeGL &attribute = mVAOState->attributes[mTexcoordAttribLocation];
1456     attribute.enabled            = true;
1457     attribute.format             = &angle::Format::Get(angle::FormatID::R32G32_FLOAT);
1458     attribute.pointer            = nullptr;
1459 
1460     VertexBindingGL &binding = mVAOState->bindings[mTexcoordAttribLocation];
1461     binding.stride           = 8;
1462     binding.offset           = 0;
1463     binding.buffer           = mVertexBuffer;
1464 
1465     if (mFeatures.syncAllVertexArraysToDefault.enabled)
1466     {
1467         mStateManager->setDefaultVAOStateDirty();
1468     }
1469 
1470     return angle::Result::Continue;
1471 }
1472 
getBlitProgram(const gl::Context * context,gl::TextureType sourceTextureType,GLenum sourceComponentType,GLenum destComponentType,BlitProgram ** program)1473 angle::Result BlitGL::getBlitProgram(const gl::Context *context,
1474                                      gl::TextureType sourceTextureType,
1475                                      GLenum sourceComponentType,
1476                                      GLenum destComponentType,
1477                                      BlitProgram **program)
1478 {
1479 
1480     BlitProgramType programType(sourceTextureType, sourceComponentType, destComponentType);
1481     BlitProgram &result = mBlitPrograms[programType];
1482     if (result.program == 0)
1483     {
1484         result.program = ANGLE_GL_TRY(context, mFunctions->createProgram());
1485 
1486         // Depending on what types need to be output by the shaders, different versions need to be
1487         // used.
1488         constexpr const char *texcoordAttribName = "a_texcoord";
1489         std::string version;
1490         std::string vsInputVariableQualifier;
1491         std::string vsOutputVariableQualifier;
1492         std::string fsInputVariableQualifier;
1493         std::string fsOutputVariableQualifier;
1494         std::string sampleFunction;
1495         if (sourceComponentType != GL_UNSIGNED_INT && destComponentType != GL_UNSIGNED_INT &&
1496             sourceTextureType != gl::TextureType::Rectangle)
1497         {
1498             // Simple case, float-to-float with 2D or external textures.  Only needs ESSL/GLSL 100
1499             version                   = "100";
1500             vsInputVariableQualifier  = "attribute";
1501             vsOutputVariableQualifier = "varying";
1502             fsInputVariableQualifier  = "varying";
1503             fsOutputVariableQualifier = "";
1504             sampleFunction            = "texture2D";
1505         }
1506         else
1507         {
1508             // Need to use a higher version to support non-float output types
1509             if (mFunctions->standard == STANDARD_GL_DESKTOP)
1510             {
1511                 version = "330";
1512             }
1513             else
1514             {
1515                 ASSERT(mFunctions->standard == STANDARD_GL_ES);
1516                 version = "300 es";
1517             }
1518             vsInputVariableQualifier  = "in";
1519             vsOutputVariableQualifier = "out";
1520             fsInputVariableQualifier  = "in";
1521             fsOutputVariableQualifier = "out";
1522             sampleFunction            = "texture";
1523         }
1524 
1525         {
1526             // Compile the vertex shader
1527             std::ostringstream vsSourceStream;
1528             vsSourceStream << "#version " << version << "\n";
1529             vsSourceStream << vsInputVariableQualifier << " vec2 " << texcoordAttribName << ";\n";
1530             vsSourceStream << "uniform vec2 u_scale;\n";
1531             vsSourceStream << "uniform vec2 u_offset;\n";
1532             vsSourceStream << vsOutputVariableQualifier << " vec2 v_texcoord;\n";
1533             vsSourceStream << "\n";
1534             vsSourceStream << "void main()\n";
1535             vsSourceStream << "{\n";
1536             vsSourceStream << "    gl_Position = vec4((" << texcoordAttribName
1537                            << " * 2.0) - 1.0, 0.0, 1.0);\n";
1538             vsSourceStream << "    v_texcoord = " << texcoordAttribName
1539                            << " * u_scale + u_offset;\n";
1540             vsSourceStream << "}\n";
1541 
1542             std::string vsSourceStr  = vsSourceStream.str();
1543             const char *vsSourceCStr = vsSourceStr.c_str();
1544 
1545             GLuint vs = ANGLE_GL_TRY(context, mFunctions->createShader(GL_VERTEX_SHADER));
1546             ANGLE_GL_TRY(context, mFunctions->shaderSource(vs, 1, &vsSourceCStr, nullptr));
1547             ANGLE_GL_TRY(context, mFunctions->compileShader(vs));
1548             ANGLE_TRY(CheckCompileStatus(context, mFunctions, vs));
1549 
1550             ANGLE_GL_TRY(context, mFunctions->attachShader(result.program, vs));
1551             ANGLE_GL_TRY(context, mFunctions->deleteShader(vs));
1552         }
1553 
1554         {
1555             // Sampling texture uniform changes depending on source texture type.
1556             std::string samplerType;
1557             switch (sourceTextureType)
1558             {
1559                 case gl::TextureType::_2D:
1560                     switch (sourceComponentType)
1561                     {
1562                         case GL_UNSIGNED_INT:
1563                             samplerType = "usampler2D";
1564                             break;
1565 
1566                         default:  // Float type
1567                             samplerType = "sampler2D";
1568                             break;
1569                     }
1570                     break;
1571 
1572                 case gl::TextureType::External:
1573                     ASSERT(sourceComponentType != GL_UNSIGNED_INT);
1574                     samplerType = "samplerExternalOES";
1575                     break;
1576 
1577                 case gl::TextureType::Rectangle:
1578                     ASSERT(sourceComponentType != GL_UNSIGNED_INT);
1579                     samplerType = "sampler2DRect";
1580                     break;
1581 
1582                 default:
1583                     UNREACHABLE();
1584                     break;
1585             }
1586 
1587             std::string samplerResultType;
1588             switch (sourceComponentType)
1589             {
1590                 case GL_UNSIGNED_INT:
1591                     samplerResultType = "uvec4";
1592                     break;
1593 
1594                 default:  // Float type
1595                     samplerResultType = "vec4";
1596                     break;
1597             }
1598 
1599             std::string extensionRequirements;
1600             switch (sourceTextureType)
1601             {
1602                 case gl::TextureType::External:
1603                     extensionRequirements = "#extension GL_OES_EGL_image_external : require";
1604                     break;
1605 
1606                 case gl::TextureType::Rectangle:
1607                     if (mFunctions->hasGLExtension("GL_ARB_texture_rectangle"))
1608                     {
1609                         extensionRequirements = "#extension GL_ARB_texture_rectangle : require";
1610                     }
1611                     else
1612                     {
1613                         ASSERT(mFunctions->isAtLeastGL(gl::Version(3, 1)));
1614                     }
1615                     break;
1616 
1617                 default:
1618                     break;
1619             }
1620 
1621             // Output variables depend on the output type
1622             std::string outputType;
1623             std::string outputVariableName;
1624             std::string outputMultiplier;
1625             switch (destComponentType)
1626             {
1627                 case GL_UNSIGNED_INT:
1628                     outputType         = "uvec4";
1629                     outputVariableName = "outputUint";
1630                     outputMultiplier   = "255.0";
1631                     break;
1632 
1633                 default:  //  float type
1634                     if (version == "100")
1635                     {
1636                         outputType         = "";
1637                         outputVariableName = "gl_FragColor";
1638                         outputMultiplier   = "1.0";
1639                     }
1640                     else
1641                     {
1642                         outputType         = "vec4";
1643                         outputVariableName = "outputFloat";
1644                         outputMultiplier   = "1.0";
1645                     }
1646                     break;
1647             }
1648 
1649             // Compile the fragment shader
1650             std::ostringstream fsSourceStream;
1651             fsSourceStream << "#version " << version << "\n";
1652             fsSourceStream << extensionRequirements << "\n";
1653             fsSourceStream << "precision highp float;\n";
1654             fsSourceStream << "uniform " << samplerType << " u_source_texture;\n";
1655 
1656             // Write the rest of the uniforms and varyings
1657             fsSourceStream << "uniform bool u_multiply_alpha;\n";
1658             fsSourceStream << "uniform bool u_unmultiply_alpha;\n";
1659             fsSourceStream << "uniform bool u_transform_linear_to_srgb;\n";
1660             fsSourceStream << fsInputVariableQualifier << " vec2 v_texcoord;\n";
1661             if (!outputType.empty())
1662             {
1663                 fsSourceStream << fsOutputVariableQualifier << " " << outputType << " "
1664                                << outputVariableName << ";\n";
1665             }
1666 
1667             // Write the linear to sRGB function.
1668             fsSourceStream << "\n";
1669             fsSourceStream << "float transformLinearToSrgb(float cl)\n";
1670             fsSourceStream << "{\n";
1671             fsSourceStream << "    if (cl <= 0.0)\n";
1672             fsSourceStream << "        return 0.0;\n";
1673             fsSourceStream << "    if (cl < 0.0031308)\n";
1674             fsSourceStream << "        return 12.92 * cl;\n";
1675             fsSourceStream << "    if (cl < 1.0)\n";
1676             fsSourceStream << "        return 1.055 * pow(cl, 0.41666) - 0.055;\n";
1677             fsSourceStream << "    return 1.0;\n";
1678             fsSourceStream << "}\n";
1679 
1680             // Write the main body
1681             fsSourceStream << "\n";
1682             fsSourceStream << "void main()\n";
1683             fsSourceStream << "{\n";
1684 
1685             std::string maxTexcoord;
1686             switch (sourceTextureType)
1687             {
1688                 case gl::TextureType::Rectangle:
1689                     // Valid texcoords are within source texture size
1690                     maxTexcoord = "vec2(textureSize(u_source_texture))";
1691                     break;
1692 
1693                 default:
1694                     // Valid texcoords are in [0, 1]
1695                     maxTexcoord = "vec2(1.0)";
1696                     break;
1697             }
1698 
1699             // discard if the texcoord is invalid so the blitframebuffer workaround doesn't
1700             // write when the point sampled is outside of the source framebuffer.
1701             fsSourceStream << "    if (clamp(v_texcoord, vec2(0.0), " << maxTexcoord
1702                            << ") != v_texcoord)\n";
1703             fsSourceStream << "    {\n";
1704             fsSourceStream << "        discard;\n";
1705             fsSourceStream << "    }\n";
1706 
1707             // Sampling code depends on the input data type
1708             fsSourceStream << "    " << samplerResultType << " color = " << sampleFunction
1709                            << "(u_source_texture, v_texcoord);\n";
1710 
1711             // Perform transformation from linear to sRGB encoding.
1712             fsSourceStream << "    if (u_transform_linear_to_srgb)\n";
1713             fsSourceStream << "    {\n";
1714             fsSourceStream << "        color.x = transformLinearToSrgb(color.x);\n";
1715             fsSourceStream << "        color.y = transformLinearToSrgb(color.y);\n";
1716             fsSourceStream << "        color.z = transformLinearToSrgb(color.z);\n";
1717             fsSourceStream << "    }\n";
1718 
1719             // Perform unmultiply-alpha if requested.
1720             fsSourceStream << "    if (u_unmultiply_alpha && color.a != 0.0)\n";
1721             fsSourceStream << "    {\n";
1722             fsSourceStream << "         color.xyz = color.xyz / color.a;\n";
1723             fsSourceStream << "    }\n";
1724 
1725             // Perform premultiply-alpha if requested.
1726             fsSourceStream << "    if (u_multiply_alpha)\n";
1727             fsSourceStream << "    {\n";
1728             fsSourceStream << "        color.xyz = color.xyz * color.a;\n";
1729             fsSourceStream << "    }\n";
1730 
1731             // Write the conversion to the destionation type
1732             fsSourceStream << "    color = color * " << outputMultiplier << ";\n";
1733 
1734             // Write the output assignment code
1735             fsSourceStream << "    " << outputVariableName << " = " << outputType << "(color);\n";
1736             fsSourceStream << "}\n";
1737 
1738             std::string fsSourceStr  = fsSourceStream.str();
1739             const char *fsSourceCStr = fsSourceStr.c_str();
1740 
1741             GLuint fs = ANGLE_GL_TRY(context, mFunctions->createShader(GL_FRAGMENT_SHADER));
1742             ANGLE_GL_TRY(context, mFunctions->shaderSource(fs, 1, &fsSourceCStr, nullptr));
1743             ANGLE_GL_TRY(context, mFunctions->compileShader(fs));
1744             ANGLE_TRY(CheckCompileStatus(context, mFunctions, fs));
1745 
1746             ANGLE_GL_TRY(context, mFunctions->attachShader(result.program, fs));
1747             ANGLE_GL_TRY(context, mFunctions->deleteShader(fs));
1748         }
1749 
1750         ANGLE_GL_TRY(context, mFunctions->bindAttribLocation(
1751                                   result.program, mTexcoordAttribLocation, texcoordAttribName));
1752         ANGLE_GL_TRY(context, mFunctions->linkProgram(result.program));
1753         ANGLE_TRY(CheckLinkStatus(context, mFunctions, result.program));
1754 
1755         result.sourceTextureLocation = ANGLE_GL_TRY(
1756             context, mFunctions->getUniformLocation(result.program, "u_source_texture"));
1757         result.scaleLocation =
1758             ANGLE_GL_TRY(context, mFunctions->getUniformLocation(result.program, "u_scale"));
1759         result.offsetLocation =
1760             ANGLE_GL_TRY(context, mFunctions->getUniformLocation(result.program, "u_offset"));
1761         result.multiplyAlphaLocation = ANGLE_GL_TRY(
1762             context, mFunctions->getUniformLocation(result.program, "u_multiply_alpha"));
1763         result.unMultiplyAlphaLocation = ANGLE_GL_TRY(
1764             context, mFunctions->getUniformLocation(result.program, "u_unmultiply_alpha"));
1765         result.transformLinearToSrgbLocation = ANGLE_GL_TRY(
1766             context, mFunctions->getUniformLocation(result.program, "u_transform_linear_to_srgb"));
1767     }
1768 
1769     *program = &result;
1770     return angle::Result::Continue;
1771 }
1772 
1773 }  // namespace rx
1774