• 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 // 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/FeaturesGL.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 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->setBlendEnabled(false);
89         stateManager->setColorMask(true, true, true, true);
90         stateManager->setSampleAlphaToCoverageEnabled(false);
91         stateManager->setSampleCoverageEnabled(false);
92         stateManager->setDepthTestEnabled(false);
93         stateManager->setStencilTestEnabled(false);
94         stateManager->setCullFaceEnabled(false);
95         stateManager->setPolygonOffsetFillEnabled(false);
96         stateManager->setRasterizerDiscardEnabled(false);
97 
98         stateManager->pauseTransformFeedback();
99         return stateManager->pauseAllQueries(context);
100     }
101 
exit(const gl::Context * context)102     angle::Result exit(const gl::Context *context)
103     {
104         mExited = true;
105 
106         ContextGL *contextGL         = GetImplAs<ContextGL>(context);
107         StateManagerGL *stateManager = contextGL->getStateManager();
108 
109         // XFB resuming will be done automatically
110         return stateManager->resumeAllQueries(context);
111     }
112 
willUseTextureUnit(const gl::Context * context,int unit)113     void willUseTextureUnit(const gl::Context *context, int unit)
114     {
115         ContextGL *contextGL = GetImplAs<ContextGL>(context);
116 
117         if (contextGL->getFunctions()->bindSampler)
118         {
119             contextGL->getStateManager()->bindSampler(unit, 0);
120         }
121     }
122 
123   private:
124     bool mExited = false;
125 };
126 
SetClearState(StateManagerGL * stateManager,bool colorClear,bool depthClear,bool stencilClear,GLbitfield * outClearMask)127 angle::Result SetClearState(StateManagerGL *stateManager,
128                             bool colorClear,
129                             bool depthClear,
130                             bool stencilClear,
131                             GLbitfield *outClearMask)
132 {
133     *outClearMask = 0;
134     if (colorClear)
135     {
136         stateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 0.0f));
137         stateManager->setColorMask(true, true, true, true);
138         *outClearMask |= GL_COLOR_BUFFER_BIT;
139     }
140     if (depthClear)
141     {
142         stateManager->setDepthMask(true);
143         stateManager->setClearDepth(1.0f);
144         *outClearMask |= GL_DEPTH_BUFFER_BIT;
145     }
146     if (stencilClear)
147     {
148         stateManager->setClearStencil(0);
149         *outClearMask |= GL_STENCIL_BUFFER_BIT;
150     }
151 
152     stateManager->setScissorTestEnabled(false);
153 
154     return angle::Result::Continue;
155 }
156 
157 using ClearBindTargetVector = angle::FixedVector<GLenum, 3>;
158 
PrepareForClear(StateManagerGL * stateManager,GLenum sizedInternalFormat,ClearBindTargetVector * outBindtargets,ClearBindTargetVector * outUnbindTargets,GLbitfield * outClearMask)159 angle::Result PrepareForClear(StateManagerGL *stateManager,
160                               GLenum sizedInternalFormat,
161                               ClearBindTargetVector *outBindtargets,
162                               ClearBindTargetVector *outUnbindTargets,
163                               GLbitfield *outClearMask)
164 {
165     const gl::InternalFormat &internalFormatInfo =
166         gl::GetSizedInternalFormatInfo(sizedInternalFormat);
167     bool bindDepth   = internalFormatInfo.depthBits > 0;
168     bool bindStencil = internalFormatInfo.stencilBits > 0;
169     bool bindColor   = !bindDepth && !bindStencil;
170 
171     outBindtargets->clear();
172     if (bindColor)
173     {
174         outBindtargets->push_back(GL_COLOR_ATTACHMENT0);
175     }
176     else
177     {
178         outUnbindTargets->push_back(GL_COLOR_ATTACHMENT0);
179     }
180     if (bindDepth)
181     {
182         outBindtargets->push_back(GL_DEPTH_ATTACHMENT);
183     }
184     else
185     {
186         outUnbindTargets->push_back(GL_DEPTH_ATTACHMENT);
187     }
188     if (bindStencil)
189     {
190         outBindtargets->push_back(GL_STENCIL_ATTACHMENT);
191     }
192     else
193     {
194         outUnbindTargets->push_back(GL_STENCIL_ATTACHMENT);
195     }
196 
197     ANGLE_TRY(SetClearState(stateManager, bindColor, bindDepth, bindStencil, outClearMask));
198 
199     return angle::Result::Continue;
200 }
201 
UnbindAttachments(const gl::Context * context,const FunctionsGL * functions,GLenum framebufferTarget,const ClearBindTargetVector & bindTargets)202 angle::Result UnbindAttachments(const gl::Context *context,
203                                 const FunctionsGL *functions,
204                                 GLenum framebufferTarget,
205                                 const ClearBindTargetVector &bindTargets)
206 {
207     for (GLenum bindTarget : bindTargets)
208     {
209         ANGLE_GL_TRY(context, functions->framebufferRenderbuffer(framebufferTarget, bindTarget,
210                                                                  GL_RENDERBUFFER, 0));
211     }
212     return angle::Result::Continue;
213 }
214 
215 }  // anonymous namespace
216 
BlitGL(const FunctionsGL * functions,const angle::FeaturesGL & features,StateManagerGL * stateManager)217 BlitGL::BlitGL(const FunctionsGL *functions,
218                const angle::FeaturesGL &features,
219                StateManagerGL *stateManager)
220     : mFunctions(functions),
221       mFeatures(features),
222       mStateManager(stateManager),
223       mScratchFBO(0),
224       mVAO(0),
225       mVertexBuffer(0)
226 {
227     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
228     {
229         mScratchTextures[i] = 0;
230     }
231 
232     ASSERT(mFunctions);
233     ASSERT(mStateManager);
234 }
235 
~BlitGL()236 BlitGL::~BlitGL()
237 {
238     for (const auto &blitProgram : mBlitPrograms)
239     {
240         mStateManager->deleteProgram(blitProgram.second.program);
241     }
242     mBlitPrograms.clear();
243 
244     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
245     {
246         if (mScratchTextures[i] != 0)
247         {
248             mStateManager->deleteTexture(mScratchTextures[i]);
249             mScratchTextures[i] = 0;
250         }
251     }
252 
253     if (mScratchFBO != 0)
254     {
255         mStateManager->deleteFramebuffer(mScratchFBO);
256         mScratchFBO = 0;
257     }
258 
259     if (mVAO != 0)
260     {
261         mStateManager->deleteVertexArray(mVAO);
262         mVAO = 0;
263     }
264 }
265 
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)266 angle::Result BlitGL::copyImageToLUMAWorkaroundTexture(const gl::Context *context,
267                                                        GLuint texture,
268                                                        gl::TextureType textureType,
269                                                        gl::TextureTarget target,
270                                                        GLenum lumaFormat,
271                                                        size_t level,
272                                                        const gl::Rectangle &sourceArea,
273                                                        GLenum internalFormat,
274                                                        gl::Framebuffer *source)
275 {
276     mStateManager->bindTexture(textureType, texture);
277 
278     // Allocate the texture memory
279     GLenum format   = gl::GetUnsizedFormat(internalFormat);
280     GLenum readType = source->getImplementationColorReadType(context);
281 
282     gl::PixelUnpackState unpack;
283     mStateManager->setPixelUnpackState(unpack);
284     mStateManager->setPixelUnpackBuffer(
285         context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack));
286     ANGLE_GL_TRY_ALWAYS_CHECK(
287         context,
288         mFunctions->texImage2D(ToGLenum(target), static_cast<GLint>(level), internalFormat,
289                                sourceArea.width, sourceArea.height, 0, format, readType, nullptr));
290 
291     return copySubImageToLUMAWorkaroundTexture(context, texture, textureType, target, lumaFormat,
292                                                level, gl::Offset(0, 0, 0), sourceArea, source);
293 }
294 
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)295 angle::Result BlitGL::copySubImageToLUMAWorkaroundTexture(const gl::Context *context,
296                                                           GLuint texture,
297                                                           gl::TextureType textureType,
298                                                           gl::TextureTarget target,
299                                                           GLenum lumaFormat,
300                                                           size_t level,
301                                                           const gl::Offset &destOffset,
302                                                           const gl::Rectangle &sourceArea,
303                                                           gl::Framebuffer *source)
304 {
305     ANGLE_TRY(initializeResources(context));
306 
307     BlitProgram *blitProgram = nullptr;
308     ANGLE_TRY(getBlitProgram(context, gl::TextureType::_2D, GL_FLOAT, GL_FLOAT, &blitProgram));
309 
310     // Blit the framebuffer to the first scratch texture
311     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
312     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
313 
314     GLenum readFormat = source->getImplementationColorReadFormat(context);
315     GLenum readType   = source->getImplementationColorReadType(context);
316 
317     nativegl::CopyTexImageImageFormat copyTexImageFormat =
318         nativegl::GetCopyTexImageImageFormat(mFunctions, mFeatures, readFormat, readType);
319 
320     mStateManager->bindTexture(gl::TextureType::_2D, mScratchTextures[0]);
321     ANGLE_GL_TRY_ALWAYS_CHECK(
322         context, mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, copyTexImageFormat.internalFormat,
323                                             sourceArea.x, sourceArea.y, sourceArea.width,
324                                             sourceArea.height, 0));
325 
326     // Set the swizzle of the scratch texture so that the channels sample into the correct emulated
327     // LUMA channels.
328     GLint swizzle[4] = {
329         (lumaFormat == GL_ALPHA) ? GL_ALPHA : GL_RED,
330         (lumaFormat == GL_LUMINANCE_ALPHA) ? GL_ALPHA : GL_ZERO,
331         GL_ZERO,
332         GL_ZERO,
333     };
334     ANGLE_GL_TRY(context,
335                  mFunctions->texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle));
336 
337     // Make a temporary framebuffer using the second scratch texture to render the swizzled result
338     // to.
339     mStateManager->bindTexture(gl::TextureType::_2D, mScratchTextures[1]);
340     ANGLE_GL_TRY_ALWAYS_CHECK(
341         context, mFunctions->texImage2D(GL_TEXTURE_2D, 0, copyTexImageFormat.internalFormat,
342                                         sourceArea.width, sourceArea.height, 0,
343                                         gl::GetUnsizedFormat(copyTexImageFormat.internalFormat),
344                                         readType, nullptr));
345 
346     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
347     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
348                                                            GL_TEXTURE_2D, mScratchTextures[1], 0));
349 
350     // Render to the destination texture, sampling from the scratch texture
351     ScopedGLState scopedState;
352     ANGLE_TRY(scopedState.enter(context, gl::Rectangle(0, 0, sourceArea.width, sourceArea.height)));
353     scopedState.willUseTextureUnit(context, 0);
354 
355     ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
356     ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
357 
358     mStateManager->activeTexture(0);
359     mStateManager->bindTexture(gl::TextureType::_2D, mScratchTextures[0]);
360 
361     mStateManager->useProgram(blitProgram->program);
362     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
363     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, 1.0, 1.0));
364     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->offsetLocation, 0.0, 0.0));
365     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
366     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
367 
368     mStateManager->bindVertexArray(mVAO, 0);
369     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
370 
371     // Copy the swizzled texture to the destination texture
372     mStateManager->bindTexture(textureType, texture);
373 
374     if (nativegl::UseTexImage3D(textureType))
375     {
376         ANGLE_GL_TRY(context,
377                      mFunctions->copyTexSubImage3D(ToGLenum(target), static_cast<GLint>(level),
378                                                    destOffset.x, destOffset.y, destOffset.z, 0, 0,
379                                                    sourceArea.width, sourceArea.height));
380     }
381     else
382     {
383         ASSERT(nativegl::UseTexImage2D(textureType));
384         ANGLE_GL_TRY(context, mFunctions->copyTexSubImage2D(
385                                   ToGLenum(target), static_cast<GLint>(level), destOffset.x,
386                                   destOffset.y, 0, 0, sourceArea.width, sourceArea.height));
387     }
388 
389     // Finally orphan the scratch textures so they can be GCed by the driver.
390     ANGLE_TRY(orphanScratchTextures(context));
391 
392     ANGLE_TRY(scopedState.exit(context));
393     return angle::Result::Continue;
394 }
395 
blitColorBufferWithShader(const gl::Context * context,const gl::Framebuffer * source,const gl::Framebuffer * dest,const gl::Rectangle & sourceAreaIn,const gl::Rectangle & destAreaIn,GLenum filter)396 angle::Result BlitGL::blitColorBufferWithShader(const gl::Context *context,
397                                                 const gl::Framebuffer *source,
398                                                 const gl::Framebuffer *dest,
399                                                 const gl::Rectangle &sourceAreaIn,
400                                                 const gl::Rectangle &destAreaIn,
401                                                 GLenum filter)
402 {
403     ANGLE_TRY(initializeResources(context));
404 
405     BlitProgram *blitProgram = nullptr;
406     ANGLE_TRY(getBlitProgram(context, gl::TextureType::_2D, GL_FLOAT, GL_FLOAT, &blitProgram));
407 
408     // We'll keep things simple by removing reversed coordinates from the rectangles. In the end
409     // we'll apply the reversal to the source texture coordinates if needed. The destination
410     // rectangle will be set to the gl viewport, which can't be reversed.
411     bool reverseX            = sourceAreaIn.isReversedX() != destAreaIn.isReversedX();
412     bool reverseY            = sourceAreaIn.isReversedY() != destAreaIn.isReversedY();
413     gl::Rectangle sourceArea = sourceAreaIn.removeReversal();
414     gl::Rectangle destArea   = destAreaIn.removeReversal();
415 
416     const gl::FramebufferAttachment *readAttachment = source->getReadColorAttachment();
417     ASSERT(readAttachment->getSamples() <= 1);
418 
419     // Compute the part of the source that will be sampled.
420     gl::Rectangle inBoundsSource;
421     {
422         gl::Extents sourceSize = readAttachment->getSize();
423         gl::Rectangle sourceBounds(0, 0, sourceSize.width, sourceSize.height);
424         if (!gl::ClipRectangle(sourceArea, sourceBounds, &inBoundsSource))
425         {
426             // Early out when the sampled part is empty as the blit will be a noop,
427             // and it prevents a division by zero in later computations.
428             return angle::Result::Continue;
429         }
430     }
431 
432     // The blit will be emulated by getting the source of the blit in a texture and sampling it
433     // with CLAMP_TO_EDGE.
434 
435     GLuint textureId;
436 
437     // TODO(cwallez) once texture dirty bits are landed, reuse attached texture instead of using
438     // CopyTexImage2D
439     {
440         textureId = mScratchTextures[0];
441 
442         GLenum format                 = readAttachment->getFormat().info->internalFormat;
443         const FramebufferGL *sourceGL = GetImplAs<FramebufferGL>(source);
444         mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceGL->getFramebufferID());
445         mStateManager->bindTexture(gl::TextureType::_2D, textureId);
446 
447         ANGLE_GL_TRY_ALWAYS_CHECK(
448             context,
449             mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, format, inBoundsSource.x, inBoundsSource.y,
450                                        inBoundsSource.width, inBoundsSource.height, 0));
451 
452         // Translate sourceArea to be relative to the copied image.
453         sourceArea.x -= inBoundsSource.x;
454         sourceArea.y -= inBoundsSource.y;
455 
456         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MIN_FILTER, filter));
457         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MAG_FILTER, filter));
458         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
459         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
460     }
461 
462     // Transform the source area to the texture coordinate space (where 0.0 and 1.0 correspond to
463     // the edges of the texture).
464     Vector2 texCoordOffset(
465         static_cast<float>(sourceArea.x) / static_cast<float>(inBoundsSource.width),
466         static_cast<float>(sourceArea.y) / static_cast<float>(inBoundsSource.height));
467     // texCoordScale is equal to the size of the source area in texture coordinates.
468     Vector2 texCoordScale(
469         static_cast<float>(sourceArea.width) / static_cast<float>(inBoundsSource.width),
470         static_cast<float>(sourceArea.height) / static_cast<float>(inBoundsSource.height));
471 
472     if (reverseX)
473     {
474         texCoordOffset.x() = texCoordOffset.x() + texCoordScale.x();
475         texCoordScale.x()  = -texCoordScale.x();
476     }
477     if (reverseY)
478     {
479         texCoordOffset.y() = texCoordOffset.y() + texCoordScale.y();
480         texCoordScale.y()  = -texCoordScale.y();
481     }
482 
483     // Reset all the state except scissor and use the viewport to draw exactly to the destination
484     // rectangle
485     ScopedGLState scopedState;
486     ANGLE_TRY(scopedState.enter(context, destArea, ScopedGLState::KEEP_SCISSOR));
487     scopedState.willUseTextureUnit(context, 0);
488 
489     // Set uniforms
490     mStateManager->activeTexture(0);
491     mStateManager->bindTexture(gl::TextureType::_2D, textureId);
492 
493     mStateManager->useProgram(blitProgram->program);
494     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
495     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, texCoordScale.x(),
496                                                 texCoordScale.y()));
497     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->offsetLocation, texCoordOffset.x(),
498                                                 texCoordOffset.y()));
499     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
500     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
501 
502     const FramebufferGL *destGL = GetImplAs<FramebufferGL>(dest);
503     mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, destGL->getFramebufferID());
504 
505     mStateManager->bindVertexArray(mVAO, 0);
506     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
507 
508     ANGLE_TRY(scopedState.exit(context));
509     return angle::Result::Continue;
510 }
511 
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 * copySucceededOut)512 angle::Result BlitGL::copySubTexture(const gl::Context *context,
513                                      TextureGL *source,
514                                      size_t sourceLevel,
515                                      GLenum sourceComponentType,
516                                      GLuint destID,
517                                      gl::TextureTarget destTarget,
518                                      size_t destLevel,
519                                      GLenum destComponentType,
520                                      const gl::Extents &sourceSize,
521                                      const gl::Rectangle &sourceArea,
522                                      const gl::Offset &destOffset,
523                                      bool needsLumaWorkaround,
524                                      GLenum lumaFormat,
525                                      bool unpackFlipY,
526                                      bool unpackPremultiplyAlpha,
527                                      bool unpackUnmultiplyAlpha,
528                                      bool *copySucceededOut)
529 {
530     ASSERT(source->getType() == gl::TextureType::_2D ||
531            source->getType() == gl::TextureType::External ||
532            source->getType() == gl::TextureType::Rectangle);
533     ANGLE_TRY(initializeResources(context));
534 
535     // Make sure the destination texture can be rendered to before setting anything else up.  Some
536     // cube maps may not be renderable until all faces have been filled.
537     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
538     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
539                                                            ToGLenum(destTarget), destID,
540                                                            static_cast<GLint>(destLevel)));
541     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
542     if (status != GL_FRAMEBUFFER_COMPLETE)
543     {
544         *copySucceededOut = false;
545         return angle::Result::Continue;
546     }
547 
548     BlitProgram *blitProgram = nullptr;
549     ANGLE_TRY(getBlitProgram(context, source->getType(), sourceComponentType, destComponentType,
550                              &blitProgram));
551 
552     // Setup the source texture
553     if (needsLumaWorkaround)
554     {
555         GLint luminance = (lumaFormat == GL_ALPHA) ? GL_ZERO : GL_RED;
556 
557         GLint alpha = GL_RED;
558         if (lumaFormat == GL_LUMINANCE)
559         {
560             alpha = GL_ONE;
561         }
562         else if (lumaFormat == GL_LUMINANCE_ALPHA)
563         {
564             alpha = GL_GREEN;
565         }
566         else
567         {
568             ASSERT(lumaFormat == GL_ALPHA);
569         }
570 
571         GLint swizzle[4] = {luminance, luminance, luminance, alpha};
572         ANGLE_TRY(source->setSwizzle(context, swizzle));
573     }
574     ANGLE_TRY(source->setMinFilter(context, GL_NEAREST));
575     ANGLE_TRY(source->setMagFilter(context, GL_NEAREST));
576     ANGLE_TRY(source->setBaseLevel(context, static_cast<GLuint>(sourceLevel)));
577 
578     // Render to the destination texture, sampling from the source texture
579     ScopedGLState scopedState;
580     ANGLE_TRY(scopedState.enter(
581         context, gl::Rectangle(destOffset.x, destOffset.y, sourceArea.width, sourceArea.height)));
582     scopedState.willUseTextureUnit(context, 0);
583 
584     mStateManager->activeTexture(0);
585     mStateManager->bindTexture(source->getType(), source->getTextureID());
586 
587     Vector2 scale(sourceArea.width, sourceArea.height);
588     Vector2 offset(sourceArea.x, sourceArea.y);
589     if (source->getType() != gl::TextureType::Rectangle)
590     {
591         scale.x() /= static_cast<float>(sourceSize.width);
592         scale.y() /= static_cast<float>(sourceSize.height);
593         offset.x() /= static_cast<float>(sourceSize.width);
594         offset.y() /= static_cast<float>(sourceSize.height);
595     }
596     if (unpackFlipY)
597     {
598         offset.y() += scale.y();
599         scale.y() = -scale.y();
600     }
601 
602     mStateManager->useProgram(blitProgram->program);
603     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
604     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, scale.x(), scale.y()));
605     ANGLE_GL_TRY(context,
606                  mFunctions->uniform2f(blitProgram->offsetLocation, offset.x(), offset.y()));
607     if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha)
608     {
609         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
610         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
611     }
612     else
613     {
614         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation,
615                                                     unpackPremultiplyAlpha));
616         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation,
617                                                     unpackUnmultiplyAlpha));
618     }
619 
620     mStateManager->bindVertexArray(mVAO, 0);
621     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
622 
623     *copySucceededOut = true;
624     ANGLE_TRY(scopedState.exit(context));
625     return angle::Result::Continue;
626 }
627 
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)628 angle::Result BlitGL::copySubTextureCPUReadback(const gl::Context *context,
629                                                 TextureGL *source,
630                                                 size_t sourceLevel,
631                                                 GLenum sourceSizedInternalFormat,
632                                                 TextureGL *dest,
633                                                 gl::TextureTarget destTarget,
634                                                 size_t destLevel,
635                                                 GLenum destFormat,
636                                                 GLenum destType,
637                                                 const gl::Extents &sourceSize,
638                                                 const gl::Rectangle &sourceArea,
639                                                 const gl::Offset &destOffset,
640                                                 bool needsLumaWorkaround,
641                                                 GLenum lumaFormat,
642                                                 bool unpackFlipY,
643                                                 bool unpackPremultiplyAlpha,
644                                                 bool unpackUnmultiplyAlpha)
645 {
646     ANGLE_TRY(initializeResources(context));
647 
648     ContextGL *contextGL = GetImplAs<ContextGL>(context);
649 
650     ASSERT(source->getType() == gl::TextureType::_2D ||
651            source->getType() == gl::TextureType::External ||
652            source->getType() == gl::TextureType::Rectangle);
653     const auto &destInternalFormatInfo = gl::GetInternalFormatInfo(destFormat, destType);
654     const gl::InternalFormat &sourceInternalFormatInfo =
655         gl::GetSizedInternalFormatInfo(sourceSizedInternalFormat);
656 
657     gl::Rectangle readPixelsArea = sourceArea;
658 
659     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
660     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
661                               GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(source->getType()),
662                               source->getTextureID(), static_cast<GLint>(sourceLevel)));
663     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
664     if (status != GL_FRAMEBUFFER_COMPLETE)
665     {
666         // The source texture cannot be read with glReadPixels. Copy it into another RGBA texture
667         // and read that back instead.
668         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
669             mFunctions, mFeatures, sourceInternalFormatInfo.internalFormat,
670             sourceInternalFormatInfo.format, sourceInternalFormatInfo.type);
671 
672         gl::TextureType scratchTextureType = gl::TextureType::_2D;
673         mStateManager->bindTexture(scratchTextureType, mScratchTextures[0]);
674         ANGLE_GL_TRY_ALWAYS_CHECK(
675             context,
676             mFunctions->texImage2D(ToGLenum(scratchTextureType), 0, texImageFormat.internalFormat,
677                                    sourceArea.width, sourceArea.height, 0, texImageFormat.format,
678                                    texImageFormat.type, nullptr));
679 
680         bool copySucceeded = false;
681         ANGLE_TRY(copySubTexture(
682             context, source, sourceLevel, sourceInternalFormatInfo.componentType,
683             mScratchTextures[0], NonCubeTextureTypeToTarget(scratchTextureType), 0,
684             sourceInternalFormatInfo.componentType, sourceSize, sourceArea, gl::Offset(0, 0, 0),
685             needsLumaWorkaround, lumaFormat, false, false, false, &copySucceeded));
686         if (!copySucceeded)
687         {
688             // No fallback options if we can't render to the scratch texture.
689             return angle::Result::Stop;
690         }
691 
692         // Bind the scratch texture as the readback texture
693         mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
694         ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
695                                                                ToGLenum(scratchTextureType),
696                                                                mScratchTextures[0], 0));
697 
698         // The scratch texture sized to sourceArea so adjust the readpixels area
699         readPixelsArea.x = 0;
700         readPixelsArea.y = 0;
701 
702         // Recheck the status
703         status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
704     }
705 
706     ASSERT(status == GL_FRAMEBUFFER_COMPLETE);
707 
708     // Create a buffer for holding the source and destination memory
709     const size_t sourcePixelSize = 4;
710     size_t sourceBufferSize      = readPixelsArea.width * readPixelsArea.height * sourcePixelSize;
711     size_t destBufferSize =
712         readPixelsArea.width * readPixelsArea.height * destInternalFormatInfo.pixelBytes;
713     angle::MemoryBuffer *buffer = nullptr;
714     ANGLE_CHECK_GL_ALLOC(contextGL,
715                          context->getScratchBuffer(sourceBufferSize + destBufferSize, &buffer));
716 
717     uint8_t *sourceMemory = buffer->data();
718     uint8_t *destMemory   = buffer->data() + sourceBufferSize;
719 
720     GLenum readPixelsFormat        = GL_NONE;
721     PixelReadFunction readFunction = nullptr;
722     if (sourceInternalFormatInfo.componentType == GL_UNSIGNED_INT)
723     {
724         readPixelsFormat = GL_RGBA_INTEGER;
725         readFunction     = angle::ReadColor<angle::R8G8B8A8, GLuint>;
726     }
727     else
728     {
729         ASSERT(sourceInternalFormatInfo.componentType != GL_INT);
730         readPixelsFormat = GL_RGBA;
731         readFunction     = angle::ReadColor<angle::R8G8B8A8, GLfloat>;
732     }
733 
734     gl::PixelUnpackState unpack;
735     unpack.alignment = 1;
736     mStateManager->setPixelUnpackState(unpack);
737     mStateManager->setPixelUnpackBuffer(nullptr);
738     ANGLE_GL_TRY(context, mFunctions->readPixels(readPixelsArea.x, readPixelsArea.y,
739                                                  readPixelsArea.width, readPixelsArea.height,
740                                                  readPixelsFormat, GL_UNSIGNED_BYTE, sourceMemory));
741 
742     angle::FormatID destFormatID =
743         angle::Format::InternalFormatToID(destInternalFormatInfo.sizedInternalFormat);
744     const auto &destFormatInfo = angle::Format::Get(destFormatID);
745     CopyImageCHROMIUM(
746         sourceMemory, readPixelsArea.width * sourcePixelSize, sourcePixelSize, 0, readFunction,
747         destMemory, readPixelsArea.width * destInternalFormatInfo.pixelBytes,
748         destInternalFormatInfo.pixelBytes, 0, destFormatInfo.pixelWriteFunction,
749         destInternalFormatInfo.format, destInternalFormatInfo.componentType, readPixelsArea.width,
750         readPixelsArea.height, 1, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
751 
752     gl::PixelPackState pack;
753     pack.alignment = 1;
754     mStateManager->setPixelPackState(pack);
755     mStateManager->setPixelPackBuffer(nullptr);
756 
757     nativegl::TexSubImageFormat texSubImageFormat =
758         nativegl::GetTexSubImageFormat(mFunctions, mFeatures, destFormat, destType);
759 
760     mStateManager->bindTexture(dest->getType(), dest->getTextureID());
761     ANGLE_GL_TRY(context, mFunctions->texSubImage2D(
762                               ToGLenum(destTarget), static_cast<GLint>(destLevel), destOffset.x,
763                               destOffset.y, readPixelsArea.width, readPixelsArea.height,
764                               texSubImageFormat.format, texSubImageFormat.type, destMemory));
765 
766     return angle::Result::Continue;
767 }
768 
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)769 angle::Result BlitGL::copyTexSubImage(const gl::Context *context,
770                                       TextureGL *source,
771                                       size_t sourceLevel,
772                                       TextureGL *dest,
773                                       gl::TextureTarget destTarget,
774                                       size_t destLevel,
775                                       const gl::Rectangle &sourceArea,
776                                       const gl::Offset &destOffset,
777                                       bool *copySucceededOut)
778 {
779     ANGLE_TRY(initializeResources(context));
780 
781     // Make sure the source texture can create a complete framebuffer before continuing.
782     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
783     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
784                               GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(source->getType()),
785                               source->getTextureID(), static_cast<GLint>(sourceLevel)));
786     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
787     if (status != GL_FRAMEBUFFER_COMPLETE)
788     {
789         *copySucceededOut = false;
790         return angle::Result::Continue;
791     }
792 
793     mStateManager->bindTexture(dest->getType(), dest->getTextureID());
794 
795     ANGLE_GL_TRY(context,
796                  mFunctions->copyTexSubImage2D(ToGLenum(destTarget), static_cast<GLint>(destLevel),
797                                                destOffset.x, destOffset.y, sourceArea.x,
798                                                sourceArea.y, sourceArea.width, sourceArea.height));
799 
800     *copySucceededOut = true;
801     return angle::Result::Continue;
802 }
803 
clearRenderableTexture(const gl::Context * context,TextureGL * source,GLenum sizedInternalFormat,int numTextureLayers,const gl::ImageIndex & imageIndex,bool * clearSucceededOut)804 angle::Result BlitGL::clearRenderableTexture(const gl::Context *context,
805                                              TextureGL *source,
806                                              GLenum sizedInternalFormat,
807                                              int numTextureLayers,
808                                              const gl::ImageIndex &imageIndex,
809                                              bool *clearSucceededOut)
810 {
811     ANGLE_TRY(initializeResources(context));
812 
813     ClearBindTargetVector bindTargets;
814     ClearBindTargetVector unbindTargets;
815     GLbitfield clearMask = 0;
816     ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &unbindTargets,
817                               &clearMask));
818 
819     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
820     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, unbindTargets));
821 
822     if (nativegl::UseTexImage2D(source->getType()))
823     {
824         ASSERT(numTextureLayers == 1);
825         for (GLenum bindTarget : bindTargets)
826         {
827             ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
828                                       GL_FRAMEBUFFER, bindTarget, ToGLenum(imageIndex.getTarget()),
829                                       source->getTextureID(), imageIndex.getLevelIndex()));
830         }
831 
832         GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
833         if (status == GL_FRAMEBUFFER_COMPLETE)
834         {
835             ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
836         }
837         else
838         {
839             ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
840             *clearSucceededOut = false;
841             return angle::Result::Continue;
842         }
843     }
844     else
845     {
846         ASSERT(nativegl::UseTexImage3D(source->getType()));
847 
848         // Check if it's possible to bind all layers of the texture at once
849         if (mFunctions->framebufferTexture && !imageIndex.hasLayer())
850         {
851             for (GLenum bindTarget : bindTargets)
852             {
853                 ANGLE_GL_TRY(context, mFunctions->framebufferTexture(GL_FRAMEBUFFER, bindTarget,
854                                                                      source->getTextureID(),
855                                                                      imageIndex.getLevelIndex()));
856             }
857 
858             GLenum status =
859                 ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
860             if (status == GL_FRAMEBUFFER_COMPLETE)
861             {
862                 ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
863             }
864             else
865             {
866                 ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
867                 *clearSucceededOut = false;
868                 return angle::Result::Continue;
869             }
870         }
871         else
872         {
873             GLint firstLayer = 0;
874             GLint layerCount = numTextureLayers;
875             if (imageIndex.hasLayer())
876             {
877                 firstLayer = imageIndex.getLayerIndex();
878                 layerCount = imageIndex.getLayerCount();
879             }
880 
881             for (GLint layer = 0; layer < layerCount; layer++)
882             {
883                 for (GLenum bindTarget : bindTargets)
884                 {
885                     ANGLE_GL_TRY(context, mFunctions->framebufferTextureLayer(
886                                               GL_FRAMEBUFFER, bindTarget, source->getTextureID(),
887                                               imageIndex.getLevelIndex(), layer + firstLayer));
888                 }
889 
890                 GLenum status =
891                     ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
892                 if (status == GL_FRAMEBUFFER_COMPLETE)
893                 {
894                     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
895                 }
896                 else
897                 {
898                     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
899                     *clearSucceededOut = false;
900                     return angle::Result::Continue;
901                 }
902             }
903         }
904     }
905 
906     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
907     *clearSucceededOut = true;
908     return angle::Result::Continue;
909 }
910 
clearRenderbuffer(const gl::Context * context,RenderbufferGL * source,GLenum sizedInternalFormat)911 angle::Result BlitGL::clearRenderbuffer(const gl::Context *context,
912                                         RenderbufferGL *source,
913                                         GLenum sizedInternalFormat)
914 {
915     ANGLE_TRY(initializeResources(context));
916 
917     ClearBindTargetVector bindTargets;
918     ClearBindTargetVector unbindTargets;
919     GLbitfield clearMask = 0;
920     ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &unbindTargets,
921                               &clearMask));
922 
923     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
924     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, unbindTargets));
925 
926     for (GLenum bindTarget : bindTargets)
927     {
928         ANGLE_GL_TRY(context,
929                      mFunctions->framebufferRenderbuffer(
930                          GL_FRAMEBUFFER, bindTarget, GL_RENDERBUFFER, source->getRenderbufferID()));
931     }
932     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
933 
934     // Unbind
935     for (GLenum bindTarget : bindTargets)
936     {
937         ANGLE_GL_TRY(context, mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, bindTarget,
938                                                                   GL_RENDERBUFFER, 0));
939     }
940 
941     return angle::Result::Continue;
942 }
943 
clearFramebuffer(const gl::Context * context,FramebufferGL * source)944 angle::Result BlitGL::clearFramebuffer(const gl::Context *context, FramebufferGL *source)
945 {
946     // initializeResources skipped because no local state is used
947 
948     // Clear all attachments
949     GLbitfield clearMask = 0;
950     ANGLE_TRY(SetClearState(mStateManager, true, true, true, &clearMask));
951 
952     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, source->getFramebufferID());
953     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
954 
955     return angle::Result::Continue;
956 }
957 
clearRenderableTextureAlphaToOne(const gl::Context * context,GLuint texture,gl::TextureTarget target,size_t level)958 angle::Result BlitGL::clearRenderableTextureAlphaToOne(const gl::Context *context,
959                                                        GLuint texture,
960                                                        gl::TextureTarget target,
961                                                        size_t level)
962 {
963     // Clearing the alpha of 3D textures is not supported/needed yet.
964     ASSERT(nativegl::UseTexImage2D(TextureTargetToType(target)));
965 
966     ANGLE_TRY(initializeResources(context));
967 
968     mStateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
969     mStateManager->setColorMask(false, false, false, true);
970     mStateManager->setScissorTestEnabled(false);
971 
972     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
973     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
974                                                            ToGLenum(target), texture,
975                                                            static_cast<GLint>(level)));
976     ANGLE_GL_TRY(context, mFunctions->clear(GL_COLOR_BUFFER_BIT));
977 
978     // Unbind the texture from the the scratch framebuffer
979     ANGLE_GL_TRY(context, mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
980                                                               GL_RENDERBUFFER, 0));
981 
982     return angle::Result::Continue;
983 }
984 
initializeResources(const gl::Context * context)985 angle::Result BlitGL::initializeResources(const gl::Context *context)
986 {
987     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
988     {
989         if (mScratchTextures[i] == 0)
990         {
991             ANGLE_GL_TRY(context, mFunctions->genTextures(1, &mScratchTextures[i]));
992         }
993     }
994 
995     if (mScratchFBO == 0)
996     {
997         ANGLE_GL_TRY(context, mFunctions->genFramebuffers(1, &mScratchFBO));
998     }
999 
1000     if (mVertexBuffer == 0)
1001     {
1002         ANGLE_GL_TRY(context, mFunctions->genBuffers(1, &mVertexBuffer));
1003         mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
1004 
1005         // Use a single, large triangle, to avoid arithmetic precision issues where fragments
1006         // with the same Y coordinate don't get exactly the same interpolated texcoord Y.
1007         float vertexData[] = {
1008             -0.5f, 0.0f, 1.5f, 0.0f, 0.5f, 2.0f,
1009         };
1010 
1011         ANGLE_GL_TRY(context, mFunctions->bufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, vertexData,
1012                                                      GL_STATIC_DRAW));
1013     }
1014 
1015     if (mVAO == 0)
1016     {
1017         ANGLE_GL_TRY(context, mFunctions->genVertexArrays(1, &mVAO));
1018 
1019         mStateManager->bindVertexArray(mVAO, 0);
1020         mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
1021 
1022         // Enable all attributes with the same buffer so that it doesn't matter what location the
1023         // texcoord attribute is assigned
1024         GLint maxAttributes = 0;
1025         ANGLE_GL_TRY(context, mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttributes));
1026 
1027         for (GLint i = 0; i < maxAttributes; i++)
1028         {
1029             ANGLE_GL_TRY(context, mFunctions->enableVertexAttribArray(i));
1030             ANGLE_GL_TRY(context,
1031                          mFunctions->vertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
1032         }
1033     }
1034 
1035     return angle::Result::Continue;
1036 }
1037 
orphanScratchTextures(const gl::Context * context)1038 angle::Result BlitGL::orphanScratchTextures(const gl::Context *context)
1039 {
1040     for (auto texture : mScratchTextures)
1041     {
1042         mStateManager->bindTexture(gl::TextureType::_2D, texture);
1043         gl::PixelUnpackState unpack;
1044         mStateManager->setPixelUnpackState(unpack);
1045         mStateManager->setPixelUnpackBuffer(nullptr);
1046         GLint swizzle[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
1047         ANGLE_GL_TRY(context,
1048                      mFunctions->texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1049         ANGLE_GL_TRY(context, mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
1050                                                      GL_UNSIGNED_BYTE, nullptr));
1051     }
1052     return angle::Result::Continue;
1053 }
1054 
setScratchTextureParameter(const gl::Context * context,GLenum param,GLenum value)1055 angle::Result BlitGL::setScratchTextureParameter(const gl::Context *context,
1056                                                  GLenum param,
1057                                                  GLenum value)
1058 {
1059     for (auto texture : mScratchTextures)
1060     {
1061         mStateManager->bindTexture(gl::TextureType::_2D, texture);
1062         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, param, value));
1063         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, param, value));
1064     }
1065     return angle::Result::Continue;
1066 }
1067 
getBlitProgram(const gl::Context * context,gl::TextureType sourceTextureType,GLenum sourceComponentType,GLenum destComponentType,BlitProgram ** program)1068 angle::Result BlitGL::getBlitProgram(const gl::Context *context,
1069                                      gl::TextureType sourceTextureType,
1070                                      GLenum sourceComponentType,
1071                                      GLenum destComponentType,
1072                                      BlitProgram **program)
1073 {
1074 
1075     BlitProgramType programType(sourceTextureType, sourceComponentType, destComponentType);
1076     BlitProgram &result = mBlitPrograms[programType];
1077     if (result.program == 0)
1078     {
1079         result.program = ANGLE_GL_TRY(context, mFunctions->createProgram());
1080 
1081         // Depending on what types need to be output by the shaders, different versions need to be
1082         // used.
1083         std::string version;
1084         std::string vsInputVariableQualifier;
1085         std::string vsOutputVariableQualifier;
1086         std::string fsInputVariableQualifier;
1087         std::string fsOutputVariableQualifier;
1088         std::string sampleFunction;
1089         if (sourceComponentType != GL_UNSIGNED_INT && destComponentType != GL_UNSIGNED_INT &&
1090             sourceTextureType != gl::TextureType::Rectangle)
1091         {
1092             // Simple case, float-to-float with 2D or external textures.  Only needs ESSL/GLSL 100
1093             version                   = "100";
1094             vsInputVariableQualifier  = "attribute";
1095             vsOutputVariableQualifier = "varying";
1096             fsInputVariableQualifier  = "varying";
1097             fsOutputVariableQualifier = "";
1098             sampleFunction            = "texture2D";
1099         }
1100         else
1101         {
1102             // Need to use a higher version to support non-float output types
1103             if (mFunctions->standard == STANDARD_GL_DESKTOP)
1104             {
1105                 version = "330";
1106             }
1107             else
1108             {
1109                 ASSERT(mFunctions->standard == STANDARD_GL_ES);
1110                 version = "300 es";
1111             }
1112             vsInputVariableQualifier  = "in";
1113             vsOutputVariableQualifier = "out";
1114             fsInputVariableQualifier  = "in";
1115             fsOutputVariableQualifier = "out";
1116             sampleFunction            = "texture";
1117         }
1118 
1119         {
1120             // Compile the vertex shader
1121             std::ostringstream vsSourceStream;
1122             vsSourceStream << "#version " << version << "\n";
1123             vsSourceStream << vsInputVariableQualifier << " vec2 a_texcoord;\n";
1124             vsSourceStream << "uniform vec2 u_scale;\n";
1125             vsSourceStream << "uniform vec2 u_offset;\n";
1126             vsSourceStream << vsOutputVariableQualifier << " vec2 v_texcoord;\n";
1127             vsSourceStream << "\n";
1128             vsSourceStream << "void main()\n";
1129             vsSourceStream << "{\n";
1130             vsSourceStream << "    gl_Position = vec4((a_texcoord * 2.0) - 1.0, 0.0, 1.0);\n";
1131             vsSourceStream << "    v_texcoord = a_texcoord * u_scale + u_offset;\n";
1132             vsSourceStream << "}\n";
1133 
1134             std::string vsSourceStr  = vsSourceStream.str();
1135             const char *vsSourceCStr = vsSourceStr.c_str();
1136 
1137             GLuint vs = ANGLE_GL_TRY(context, mFunctions->createShader(GL_VERTEX_SHADER));
1138             ANGLE_GL_TRY(context, mFunctions->shaderSource(vs, 1, &vsSourceCStr, nullptr));
1139             ANGLE_GL_TRY(context, mFunctions->compileShader(vs));
1140             ANGLE_TRY(CheckCompileStatus(context, mFunctions, vs));
1141 
1142             ANGLE_GL_TRY(context, mFunctions->attachShader(result.program, vs));
1143             ANGLE_GL_TRY(context, mFunctions->deleteShader(vs));
1144         }
1145 
1146         {
1147             // Sampling texture uniform changes depending on source texture type.
1148             std::string samplerType;
1149             switch (sourceTextureType)
1150             {
1151                 case gl::TextureType::_2D:
1152                     switch (sourceComponentType)
1153                     {
1154                         case GL_UNSIGNED_INT:
1155                             samplerType = "usampler2D";
1156                             break;
1157 
1158                         default:  // Float type
1159                             samplerType = "sampler2D";
1160                             break;
1161                     }
1162                     break;
1163 
1164                 case gl::TextureType::External:
1165                     ASSERT(sourceComponentType != GL_UNSIGNED_INT);
1166                     samplerType = "samplerExternalOES";
1167                     break;
1168 
1169                 case gl::TextureType::Rectangle:
1170                     ASSERT(sourceComponentType != GL_UNSIGNED_INT);
1171                     samplerType = "sampler2DRect";
1172                     break;
1173 
1174                 default:
1175                     UNREACHABLE();
1176                     break;
1177             }
1178 
1179             std::string samplerResultType;
1180             switch (sourceComponentType)
1181             {
1182                 case GL_UNSIGNED_INT:
1183                     samplerResultType = "uvec4";
1184                     break;
1185 
1186                 default:  // Float type
1187                     samplerResultType = "vec4";
1188                     break;
1189             }
1190 
1191             std::string extensionRequirements;
1192             switch (sourceTextureType)
1193             {
1194                 case gl::TextureType::External:
1195                     extensionRequirements = "#extension GL_OES_EGL_image_external : require";
1196                     break;
1197 
1198                 case gl::TextureType::Rectangle:
1199                     if (mFunctions->hasGLExtension("GL_ARB_texture_rectangle"))
1200                     {
1201                         extensionRequirements = "#extension GL_ARB_texture_rectangle : require";
1202                     }
1203                     else
1204                     {
1205                         ASSERT(mFunctions->isAtLeastGL(gl::Version(3, 1)));
1206                     }
1207                     break;
1208 
1209                 default:
1210                     break;
1211             }
1212 
1213             // Output variables depend on the output type
1214             std::string outputType;
1215             std::string outputVariableName;
1216             std::string outputMultiplier;
1217             switch (destComponentType)
1218             {
1219                 case GL_UNSIGNED_INT:
1220                     outputType         = "uvec4";
1221                     outputVariableName = "outputUint";
1222                     outputMultiplier   = "255.0";
1223                     break;
1224 
1225                 default:  //  float type
1226                     if (version == "100")
1227                     {
1228                         outputType         = "";
1229                         outputVariableName = "gl_FragColor";
1230                         outputMultiplier   = "1.0";
1231                     }
1232                     else
1233                     {
1234                         outputType         = "vec4";
1235                         outputVariableName = "outputFloat";
1236                         outputMultiplier   = "1.0";
1237                     }
1238                     break;
1239             }
1240 
1241             // Compile the fragment shader
1242             std::ostringstream fsSourceStream;
1243             fsSourceStream << "#version " << version << "\n";
1244             fsSourceStream << extensionRequirements << "\n";
1245             fsSourceStream << "precision highp float;\n";
1246             fsSourceStream << "uniform " << samplerType << " u_source_texture;\n";
1247 
1248             // Write the rest of the uniforms and varyings
1249             fsSourceStream << "uniform bool u_multiply_alpha;\n";
1250             fsSourceStream << "uniform bool u_unmultiply_alpha;\n";
1251             fsSourceStream << fsInputVariableQualifier << " vec2 v_texcoord;\n";
1252             if (!outputType.empty())
1253             {
1254                 fsSourceStream << fsOutputVariableQualifier << " " << outputType << " "
1255                                << outputVariableName << ";\n";
1256             }
1257 
1258             // Write the main body
1259             fsSourceStream << "\n";
1260             fsSourceStream << "void main()\n";
1261             fsSourceStream << "{\n";
1262 
1263             std::string maxTexcoord;
1264             switch (sourceTextureType)
1265             {
1266                 case gl::TextureType::Rectangle:
1267                     // Valid texcoords are within source texture size
1268                     maxTexcoord = "vec2(textureSize(u_source_texture))";
1269                     break;
1270 
1271                 default:
1272                     // Valid texcoords are in [0, 1]
1273                     maxTexcoord = "vec2(1.0)";
1274                     break;
1275             }
1276 
1277             // discard if the texcoord is invalid so the blitframebuffer workaround doesn't
1278             // write when the point sampled is outside of the source framebuffer.
1279             fsSourceStream << "    if (clamp(v_texcoord, vec2(0.0), " << maxTexcoord
1280                            << ") != v_texcoord)\n";
1281             fsSourceStream << "    {\n";
1282             fsSourceStream << "        discard;\n";
1283             fsSourceStream << "    }\n";
1284 
1285             // Sampling code depends on the input data type
1286             fsSourceStream << "    " << samplerResultType << " color = " << sampleFunction
1287                            << "(u_source_texture, v_texcoord);\n";
1288 
1289             // Perform the premultiply or unmultiply alpha logic
1290             fsSourceStream << "    if (u_multiply_alpha)\n";
1291             fsSourceStream << "    {\n";
1292             fsSourceStream << "        color.xyz = color.xyz * color.a;\n";
1293             fsSourceStream << "    }\n";
1294             fsSourceStream << "    if (u_unmultiply_alpha && color.a != 0.0)\n";
1295             fsSourceStream << "    {\n";
1296             fsSourceStream << "         color.xyz = color.xyz / color.a;\n";
1297             fsSourceStream << "    }\n";
1298 
1299             // Write the conversion to the destionation type
1300             fsSourceStream << "    color = color * " << outputMultiplier << ";\n";
1301 
1302             // Write the output assignment code
1303             fsSourceStream << "    " << outputVariableName << " = " << outputType << "(color);\n";
1304             fsSourceStream << "}\n";
1305 
1306             std::string fsSourceStr  = fsSourceStream.str();
1307             const char *fsSourceCStr = fsSourceStr.c_str();
1308 
1309             GLuint fs = ANGLE_GL_TRY(context, mFunctions->createShader(GL_FRAGMENT_SHADER));
1310             ANGLE_GL_TRY(context, mFunctions->shaderSource(fs, 1, &fsSourceCStr, nullptr));
1311             ANGLE_GL_TRY(context, mFunctions->compileShader(fs));
1312             ANGLE_TRY(CheckCompileStatus(context, mFunctions, fs));
1313 
1314             ANGLE_GL_TRY(context, mFunctions->attachShader(result.program, fs));
1315             ANGLE_GL_TRY(context, mFunctions->deleteShader(fs));
1316         }
1317 
1318         ANGLE_GL_TRY(context, mFunctions->linkProgram(result.program));
1319         ANGLE_TRY(CheckLinkStatus(context, mFunctions, result.program));
1320 
1321         result.sourceTextureLocation = ANGLE_GL_TRY(
1322             context, mFunctions->getUniformLocation(result.program, "u_source_texture"));
1323         result.scaleLocation =
1324             ANGLE_GL_TRY(context, mFunctions->getUniformLocation(result.program, "u_scale"));
1325         result.offsetLocation =
1326             ANGLE_GL_TRY(context, mFunctions->getUniformLocation(result.program, "u_offset"));
1327         result.multiplyAlphaLocation = ANGLE_GL_TRY(
1328             context, mFunctions->getUniformLocation(result.program, "u_multiply_alpha"));
1329         result.unMultiplyAlphaLocation = ANGLE_GL_TRY(
1330             context, mFunctions->getUniformLocation(result.program, "u_unmultiply_alpha"));
1331     }
1332 
1333     *program = &result;
1334     return angle::Result::Continue;
1335 }
1336 
1337 }  // namespace rx
1338