757168cea3ed2a511fc2ea2d3179780bec084395
[WebKit-https.git] / Source / ThirdParty / ANGLE / src / libANGLE / renderer / gl / BlitGL.cpp
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
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
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
73     ScopedGLState() {}
74
75     ~ScopedGLState() { ASSERT(mExited); }
76
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
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
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
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
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
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
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
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
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
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
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                                                 bool writeAlpha)
403 {
404     ANGLE_TRY(initializeResources(context));
405
406     BlitProgram *blitProgram = nullptr;
407     ANGLE_TRY(getBlitProgram(context, gl::TextureType::_2D, GL_FLOAT, GL_FLOAT, &blitProgram));
408
409     // We'll keep things simple by removing reversed coordinates from the rectangles. In the end
410     // we'll apply the reversal to the source texture coordinates if needed. The destination
411     // rectangle will be set to the gl viewport, which can't be reversed.
412     bool reverseX            = sourceAreaIn.isReversedX() != destAreaIn.isReversedX();
413     bool reverseY            = sourceAreaIn.isReversedY() != destAreaIn.isReversedY();
414     gl::Rectangle sourceArea = sourceAreaIn.removeReversal();
415     gl::Rectangle destArea   = destAreaIn.removeReversal();
416
417     const gl::FramebufferAttachment *readAttachment = source->getReadColorAttachment();
418     ASSERT(readAttachment->getSamples() <= 1);
419
420     // Compute the part of the source that will be sampled.
421     gl::Rectangle inBoundsSource;
422     {
423         gl::Extents sourceSize = readAttachment->getSize();
424         gl::Rectangle sourceBounds(0, 0, sourceSize.width, sourceSize.height);
425         if (!gl::ClipRectangle(sourceArea, sourceBounds, &inBoundsSource))
426         {
427             // Early out when the sampled part is empty as the blit will be a noop,
428             // and it prevents a division by zero in later computations.
429             return angle::Result::Continue;
430         }
431     }
432
433     // The blit will be emulated by getting the source of the blit in a texture and sampling it
434     // with CLAMP_TO_EDGE.
435
436     GLuint textureId;
437
438     // TODO(cwallez) once texture dirty bits are landed, reuse attached texture instead of using
439     // CopyTexImage2D
440     {
441         textureId = mScratchTextures[0];
442
443         const gl::InternalFormat &sourceInternalFormat       = *readAttachment->getFormat().info;
444         nativegl::CopyTexImageImageFormat copyTexImageFormat = nativegl::GetCopyTexImageImageFormat(
445             mFunctions, mFeatures, sourceInternalFormat.internalFormat, sourceInternalFormat.type);
446         const FramebufferGL *sourceGL = GetImplAs<FramebufferGL>(source);
447         mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceGL->getFramebufferID());
448         mStateManager->bindTexture(gl::TextureType::_2D, textureId);
449
450         ANGLE_GL_TRY_ALWAYS_CHECK(
451             context, mFunctions->copyTexImage2D(GL_TEXTURE_2D, 0, copyTexImageFormat.internalFormat,
452                                                 inBoundsSource.x, inBoundsSource.y,
453                                                 inBoundsSource.width, inBoundsSource.height, 0));
454
455         // Translate sourceArea to be relative to the copied image.
456         sourceArea.x -= inBoundsSource.x;
457         sourceArea.y -= inBoundsSource.y;
458
459         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MIN_FILTER, filter));
460         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_MAG_FILTER, filter));
461         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
462         ANGLE_TRY(setScratchTextureParameter(context, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
463     }
464
465     // Transform the source area to the texture coordinate space (where 0.0 and 1.0 correspond to
466     // the edges of the texture).
467     Vector2 texCoordOffset(
468         static_cast<float>(sourceArea.x) / static_cast<float>(inBoundsSource.width),
469         static_cast<float>(sourceArea.y) / static_cast<float>(inBoundsSource.height));
470     // texCoordScale is equal to the size of the source area in texture coordinates.
471     Vector2 texCoordScale(
472         static_cast<float>(sourceArea.width) / static_cast<float>(inBoundsSource.width),
473         static_cast<float>(sourceArea.height) / static_cast<float>(inBoundsSource.height));
474
475     if (reverseX)
476     {
477         texCoordOffset.x() = texCoordOffset.x() + texCoordScale.x();
478         texCoordScale.x()  = -texCoordScale.x();
479     }
480     if (reverseY)
481     {
482         texCoordOffset.y() = texCoordOffset.y() + texCoordScale.y();
483         texCoordScale.y()  = -texCoordScale.y();
484     }
485
486     // Reset all the state except scissor and use the viewport to draw exactly to the destination
487     // rectangle
488     ScopedGLState scopedState;
489     ANGLE_TRY(scopedState.enter(context, destArea, ScopedGLState::KEEP_SCISSOR));
490     scopedState.willUseTextureUnit(context, 0);
491
492     // Set the write color mask to potentially not write alpha
493     mStateManager->setColorMask(true, true, true, writeAlpha);
494
495     // Set uniforms
496     mStateManager->activeTexture(0);
497     mStateManager->bindTexture(gl::TextureType::_2D, textureId);
498
499     mStateManager->useProgram(blitProgram->program);
500     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
501     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, texCoordScale.x(),
502                                                 texCoordScale.y()));
503     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->offsetLocation, texCoordOffset.x(),
504                                                 texCoordOffset.y()));
505     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
506     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
507
508     const FramebufferGL *destGL = GetImplAs<FramebufferGL>(dest);
509     mStateManager->bindFramebuffer(GL_DRAW_FRAMEBUFFER, destGL->getFramebufferID());
510
511     mStateManager->bindVertexArray(mVAO, 0);
512     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
513
514     ANGLE_TRY(scopedState.exit(context));
515     return angle::Result::Continue;
516 }
517
518 angle::Result BlitGL::copySubTexture(const gl::Context *context,
519                                      TextureGL *source,
520                                      size_t sourceLevel,
521                                      GLenum sourceComponentType,
522                                      GLuint destID,
523                                      gl::TextureTarget destTarget,
524                                      size_t destLevel,
525                                      GLenum destComponentType,
526                                      const gl::Extents &sourceSize,
527                                      const gl::Rectangle &sourceArea,
528                                      const gl::Offset &destOffset,
529                                      bool needsLumaWorkaround,
530                                      GLenum lumaFormat,
531                                      bool unpackFlipY,
532                                      bool unpackPremultiplyAlpha,
533                                      bool unpackUnmultiplyAlpha,
534                                      bool *copySucceededOut)
535 {
536     ASSERT(source->getType() == gl::TextureType::_2D ||
537            source->getType() == gl::TextureType::External ||
538            source->getType() == gl::TextureType::Rectangle);
539     ANGLE_TRY(initializeResources(context));
540
541     // Make sure the destination texture can be rendered to before setting anything else up.  Some
542     // cube maps may not be renderable until all faces have been filled.
543     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
544     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
545                                                            ToGLenum(destTarget), destID,
546                                                            static_cast<GLint>(destLevel)));
547     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
548     if (status != GL_FRAMEBUFFER_COMPLETE)
549     {
550         *copySucceededOut = false;
551         return angle::Result::Continue;
552     }
553
554     BlitProgram *blitProgram = nullptr;
555     ANGLE_TRY(getBlitProgram(context, source->getType(), sourceComponentType, destComponentType,
556                              &blitProgram));
557
558     // Setup the source texture
559     if (needsLumaWorkaround)
560     {
561         GLint luminance = (lumaFormat == GL_ALPHA) ? GL_ZERO : GL_RED;
562
563         GLint alpha = GL_RED;
564         if (lumaFormat == GL_LUMINANCE)
565         {
566             alpha = GL_ONE;
567         }
568         else if (lumaFormat == GL_LUMINANCE_ALPHA)
569         {
570             alpha = GL_GREEN;
571         }
572         else
573         {
574             ASSERT(lumaFormat == GL_ALPHA);
575         }
576
577         GLint swizzle[4] = {luminance, luminance, luminance, alpha};
578         ANGLE_TRY(source->setSwizzle(context, swizzle));
579     }
580     ANGLE_TRY(source->setMinFilter(context, GL_NEAREST));
581     ANGLE_TRY(source->setMagFilter(context, GL_NEAREST));
582     ANGLE_TRY(source->setBaseLevel(context, static_cast<GLuint>(sourceLevel)));
583
584     // Render to the destination texture, sampling from the source texture
585     ScopedGLState scopedState;
586     ANGLE_TRY(scopedState.enter(
587         context, gl::Rectangle(destOffset.x, destOffset.y, sourceArea.width, sourceArea.height)));
588     scopedState.willUseTextureUnit(context, 0);
589
590     mStateManager->activeTexture(0);
591     mStateManager->bindTexture(source->getType(), source->getTextureID());
592
593     Vector2 scale(sourceArea.width, sourceArea.height);
594     Vector2 offset(sourceArea.x, sourceArea.y);
595     if (source->getType() != gl::TextureType::Rectangle)
596     {
597         scale.x() /= static_cast<float>(sourceSize.width);
598         scale.y() /= static_cast<float>(sourceSize.height);
599         offset.x() /= static_cast<float>(sourceSize.width);
600         offset.y() /= static_cast<float>(sourceSize.height);
601     }
602     if (unpackFlipY)
603     {
604         offset.y() += scale.y();
605         scale.y() = -scale.y();
606     }
607
608     mStateManager->useProgram(blitProgram->program);
609     ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->sourceTextureLocation, 0));
610     ANGLE_GL_TRY(context, mFunctions->uniform2f(blitProgram->scaleLocation, scale.x(), scale.y()));
611     ANGLE_GL_TRY(context,
612                  mFunctions->uniform2f(blitProgram->offsetLocation, offset.x(), offset.y()));
613     if (unpackPremultiplyAlpha == unpackUnmultiplyAlpha)
614     {
615         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation, 0));
616         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation, 0));
617     }
618     else
619     {
620         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->multiplyAlphaLocation,
621                                                     unpackPremultiplyAlpha));
622         ANGLE_GL_TRY(context, mFunctions->uniform1i(blitProgram->unMultiplyAlphaLocation,
623                                                     unpackUnmultiplyAlpha));
624     }
625
626     mStateManager->bindVertexArray(mVAO, 0);
627     ANGLE_GL_TRY(context, mFunctions->drawArrays(GL_TRIANGLES, 0, 3));
628
629     *copySucceededOut = true;
630     ANGLE_TRY(scopedState.exit(context));
631     return angle::Result::Continue;
632 }
633
634 angle::Result BlitGL::copySubTextureCPUReadback(const gl::Context *context,
635                                                 TextureGL *source,
636                                                 size_t sourceLevel,
637                                                 GLenum sourceSizedInternalFormat,
638                                                 TextureGL *dest,
639                                                 gl::TextureTarget destTarget,
640                                                 size_t destLevel,
641                                                 GLenum destFormat,
642                                                 GLenum destType,
643                                                 const gl::Extents &sourceSize,
644                                                 const gl::Rectangle &sourceArea,
645                                                 const gl::Offset &destOffset,
646                                                 bool needsLumaWorkaround,
647                                                 GLenum lumaFormat,
648                                                 bool unpackFlipY,
649                                                 bool unpackPremultiplyAlpha,
650                                                 bool unpackUnmultiplyAlpha)
651 {
652     ANGLE_TRY(initializeResources(context));
653
654     ContextGL *contextGL = GetImplAs<ContextGL>(context);
655
656     ASSERT(source->getType() == gl::TextureType::_2D ||
657            source->getType() == gl::TextureType::External ||
658            source->getType() == gl::TextureType::Rectangle);
659     const auto &destInternalFormatInfo = gl::GetInternalFormatInfo(destFormat, destType);
660     const gl::InternalFormat &sourceInternalFormatInfo =
661         gl::GetSizedInternalFormatInfo(sourceSizedInternalFormat);
662
663     gl::Rectangle readPixelsArea = sourceArea;
664
665     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
666     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
667                               GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(source->getType()),
668                               source->getTextureID(), static_cast<GLint>(sourceLevel)));
669     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
670     if (status != GL_FRAMEBUFFER_COMPLETE)
671     {
672         // The source texture cannot be read with glReadPixels. Copy it into another RGBA texture
673         // and read that back instead.
674         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
675             mFunctions, mFeatures, sourceInternalFormatInfo.internalFormat,
676             sourceInternalFormatInfo.format, sourceInternalFormatInfo.type);
677
678         gl::TextureType scratchTextureType = gl::TextureType::_2D;
679         mStateManager->bindTexture(scratchTextureType, mScratchTextures[0]);
680         ANGLE_GL_TRY_ALWAYS_CHECK(
681             context,
682             mFunctions->texImage2D(ToGLenum(scratchTextureType), 0, texImageFormat.internalFormat,
683                                    sourceArea.width, sourceArea.height, 0, texImageFormat.format,
684                                    texImageFormat.type, nullptr));
685
686         bool copySucceeded = false;
687         ANGLE_TRY(copySubTexture(
688             context, source, sourceLevel, sourceInternalFormatInfo.componentType,
689             mScratchTextures[0], NonCubeTextureTypeToTarget(scratchTextureType), 0,
690             sourceInternalFormatInfo.componentType, sourceSize, sourceArea, gl::Offset(0, 0, 0),
691             needsLumaWorkaround, lumaFormat, false, false, false, &copySucceeded));
692         if (!copySucceeded)
693         {
694             // No fallback options if we can't render to the scratch texture.
695             return angle::Result::Stop;
696         }
697
698         // Bind the scratch texture as the readback texture
699         mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
700         ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
701                                                                ToGLenum(scratchTextureType),
702                                                                mScratchTextures[0], 0));
703
704         // The scratch texture sized to sourceArea so adjust the readpixels area
705         readPixelsArea.x = 0;
706         readPixelsArea.y = 0;
707
708         // Recheck the status
709         status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
710     }
711
712     ASSERT(status == GL_FRAMEBUFFER_COMPLETE);
713
714     // Create a buffer for holding the source and destination memory
715     const size_t sourcePixelSize = 4;
716     size_t sourceBufferSize      = readPixelsArea.width * readPixelsArea.height * sourcePixelSize;
717     size_t destBufferSize =
718         readPixelsArea.width * readPixelsArea.height * destInternalFormatInfo.pixelBytes;
719     angle::MemoryBuffer *buffer = nullptr;
720     ANGLE_CHECK_GL_ALLOC(contextGL,
721                          context->getScratchBuffer(sourceBufferSize + destBufferSize, &buffer));
722
723     uint8_t *sourceMemory = buffer->data();
724     uint8_t *destMemory   = buffer->data() + sourceBufferSize;
725
726     GLenum readPixelsFormat        = GL_NONE;
727     PixelReadFunction readFunction = nullptr;
728     if (sourceInternalFormatInfo.componentType == GL_UNSIGNED_INT)
729     {
730         readPixelsFormat = GL_RGBA_INTEGER;
731         readFunction     = angle::ReadColor<angle::R8G8B8A8, GLuint>;
732     }
733     else
734     {
735         ASSERT(sourceInternalFormatInfo.componentType != GL_INT);
736         readPixelsFormat = GL_RGBA;
737         readFunction     = angle::ReadColor<angle::R8G8B8A8, GLfloat>;
738     }
739
740     gl::PixelUnpackState unpack;
741     unpack.alignment = 1;
742     mStateManager->setPixelUnpackState(unpack);
743     mStateManager->setPixelUnpackBuffer(nullptr);
744     ANGLE_GL_TRY(context, mFunctions->readPixels(readPixelsArea.x, readPixelsArea.y,
745                                                  readPixelsArea.width, readPixelsArea.height,
746                                                  readPixelsFormat, GL_UNSIGNED_BYTE, sourceMemory));
747
748     angle::FormatID destFormatID =
749         angle::Format::InternalFormatToID(destInternalFormatInfo.sizedInternalFormat);
750     const auto &destFormatInfo = angle::Format::Get(destFormatID);
751     CopyImageCHROMIUM(
752         sourceMemory, readPixelsArea.width * sourcePixelSize, sourcePixelSize, 0, readFunction,
753         destMemory, readPixelsArea.width * destInternalFormatInfo.pixelBytes,
754         destInternalFormatInfo.pixelBytes, 0, destFormatInfo.pixelWriteFunction,
755         destInternalFormatInfo.format, destInternalFormatInfo.componentType, readPixelsArea.width,
756         readPixelsArea.height, 1, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
757
758     gl::PixelPackState pack;
759     pack.alignment = 1;
760     mStateManager->setPixelPackState(pack);
761     mStateManager->setPixelPackBuffer(nullptr);
762
763     nativegl::TexSubImageFormat texSubImageFormat =
764         nativegl::GetTexSubImageFormat(mFunctions, mFeatures, destFormat, destType);
765
766     mStateManager->bindTexture(dest->getType(), dest->getTextureID());
767     ANGLE_GL_TRY(context, mFunctions->texSubImage2D(
768                               ToGLenum(destTarget), static_cast<GLint>(destLevel), destOffset.x,
769                               destOffset.y, readPixelsArea.width, readPixelsArea.height,
770                               texSubImageFormat.format, texSubImageFormat.type, destMemory));
771
772     return angle::Result::Continue;
773 }
774
775 angle::Result BlitGL::copyTexSubImage(const gl::Context *context,
776                                       TextureGL *source,
777                                       size_t sourceLevel,
778                                       TextureGL *dest,
779                                       gl::TextureTarget destTarget,
780                                       size_t destLevel,
781                                       const gl::Rectangle &sourceArea,
782                                       const gl::Offset &destOffset,
783                                       bool *copySucceededOut)
784 {
785     ANGLE_TRY(initializeResources(context));
786
787     // Make sure the source texture can create a complete framebuffer before continuing.
788     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
789     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
790                               GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, ToGLenum(source->getType()),
791                               source->getTextureID(), static_cast<GLint>(sourceLevel)));
792     GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
793     if (status != GL_FRAMEBUFFER_COMPLETE)
794     {
795         *copySucceededOut = false;
796         return angle::Result::Continue;
797     }
798
799     mStateManager->bindTexture(dest->getType(), dest->getTextureID());
800
801     ANGLE_GL_TRY(context,
802                  mFunctions->copyTexSubImage2D(ToGLenum(destTarget), static_cast<GLint>(destLevel),
803                                                destOffset.x, destOffset.y, sourceArea.x,
804                                                sourceArea.y, sourceArea.width, sourceArea.height));
805
806     *copySucceededOut = true;
807     return angle::Result::Continue;
808 }
809
810 angle::Result BlitGL::clearRenderableTexture(const gl::Context *context,
811                                              TextureGL *source,
812                                              GLenum sizedInternalFormat,
813                                              int numTextureLayers,
814                                              const gl::ImageIndex &imageIndex,
815                                              bool *clearSucceededOut)
816 {
817     ANGLE_TRY(initializeResources(context));
818
819     ClearBindTargetVector bindTargets;
820     ClearBindTargetVector unbindTargets;
821     GLbitfield clearMask = 0;
822     ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &unbindTargets,
823                               &clearMask));
824
825     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
826     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, unbindTargets));
827
828     if (nativegl::UseTexImage2D(source->getType()))
829     {
830         ASSERT(numTextureLayers == 1);
831         for (GLenum bindTarget : bindTargets)
832         {
833             ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(
834                                       GL_FRAMEBUFFER, bindTarget, ToGLenum(imageIndex.getTarget()),
835                                       source->getTextureID(), imageIndex.getLevelIndex()));
836         }
837
838         GLenum status = ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
839         if (status == GL_FRAMEBUFFER_COMPLETE)
840         {
841             ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
842         }
843         else
844         {
845             ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
846             *clearSucceededOut = false;
847             return angle::Result::Continue;
848         }
849     }
850     else
851     {
852         ASSERT(nativegl::UseTexImage3D(source->getType()));
853
854         // Check if it's possible to bind all layers of the texture at once
855         if (mFunctions->framebufferTexture && !imageIndex.hasLayer())
856         {
857             for (GLenum bindTarget : bindTargets)
858             {
859                 ANGLE_GL_TRY(context, mFunctions->framebufferTexture(GL_FRAMEBUFFER, bindTarget,
860                                                                      source->getTextureID(),
861                                                                      imageIndex.getLevelIndex()));
862             }
863
864             GLenum status =
865                 ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
866             if (status == GL_FRAMEBUFFER_COMPLETE)
867             {
868                 ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
869             }
870             else
871             {
872                 ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
873                 *clearSucceededOut = false;
874                 return angle::Result::Continue;
875             }
876         }
877         else
878         {
879             GLint firstLayer = 0;
880             GLint layerCount = numTextureLayers;
881             if (imageIndex.hasLayer())
882             {
883                 firstLayer = imageIndex.getLayerIndex();
884                 layerCount = imageIndex.getLayerCount();
885             }
886
887             for (GLint layer = 0; layer < layerCount; layer++)
888             {
889                 for (GLenum bindTarget : bindTargets)
890                 {
891                     ANGLE_GL_TRY(context, mFunctions->framebufferTextureLayer(
892                                               GL_FRAMEBUFFER, bindTarget, source->getTextureID(),
893                                               imageIndex.getLevelIndex(), layer + firstLayer));
894                 }
895
896                 GLenum status =
897                     ANGLE_GL_TRY(context, mFunctions->checkFramebufferStatus(GL_FRAMEBUFFER));
898                 if (status == GL_FRAMEBUFFER_COMPLETE)
899                 {
900                     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
901                 }
902                 else
903                 {
904                     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
905                     *clearSucceededOut = false;
906                     return angle::Result::Continue;
907                 }
908             }
909         }
910     }
911
912     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, bindTargets));
913     *clearSucceededOut = true;
914     return angle::Result::Continue;
915 }
916
917 angle::Result BlitGL::clearRenderbuffer(const gl::Context *context,
918                                         RenderbufferGL *source,
919                                         GLenum sizedInternalFormat)
920 {
921     ANGLE_TRY(initializeResources(context));
922
923     ClearBindTargetVector bindTargets;
924     ClearBindTargetVector unbindTargets;
925     GLbitfield clearMask = 0;
926     ANGLE_TRY(PrepareForClear(mStateManager, sizedInternalFormat, &bindTargets, &unbindTargets,
927                               &clearMask));
928
929     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
930     ANGLE_TRY(UnbindAttachments(context, mFunctions, GL_FRAMEBUFFER, unbindTargets));
931
932     for (GLenum bindTarget : bindTargets)
933     {
934         ANGLE_GL_TRY(context,
935                      mFunctions->framebufferRenderbuffer(
936                          GL_FRAMEBUFFER, bindTarget, GL_RENDERBUFFER, source->getRenderbufferID()));
937     }
938     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
939
940     // Unbind
941     for (GLenum bindTarget : bindTargets)
942     {
943         ANGLE_GL_TRY(context, mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, bindTarget,
944                                                                   GL_RENDERBUFFER, 0));
945     }
946
947     return angle::Result::Continue;
948 }
949
950 angle::Result BlitGL::clearFramebuffer(const gl::Context *context, FramebufferGL *source)
951 {
952     // initializeResources skipped because no local state is used
953
954     // Clear all attachments
955     GLbitfield clearMask = 0;
956     ANGLE_TRY(SetClearState(mStateManager, true, true, true, &clearMask));
957
958     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, source->getFramebufferID());
959     ANGLE_GL_TRY(context, mFunctions->clear(clearMask));
960
961     return angle::Result::Continue;
962 }
963
964 angle::Result BlitGL::clearRenderableTextureAlphaToOne(const gl::Context *context,
965                                                        GLuint texture,
966                                                        gl::TextureTarget target,
967                                                        size_t level)
968 {
969     // Clearing the alpha of 3D textures is not supported/needed yet.
970     ASSERT(nativegl::UseTexImage2D(TextureTargetToType(target)));
971
972     ANGLE_TRY(initializeResources(context));
973
974     mStateManager->setClearColor(gl::ColorF(0.0f, 0.0f, 0.0f, 1.0f));
975     mStateManager->setColorMask(false, false, false, true);
976     mStateManager->setScissorTestEnabled(false);
977
978     mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mScratchFBO);
979     ANGLE_GL_TRY(context, mFunctions->framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
980                                                            ToGLenum(target), texture,
981                                                            static_cast<GLint>(level)));
982     ANGLE_GL_TRY(context, mFunctions->clear(GL_COLOR_BUFFER_BIT));
983
984     // Unbind the texture from the the scratch framebuffer
985     ANGLE_GL_TRY(context, mFunctions->framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
986                                                               GL_RENDERBUFFER, 0));
987
988     return angle::Result::Continue;
989 }
990
991 angle::Result BlitGL::initializeResources(const gl::Context *context)
992 {
993     for (size_t i = 0; i < ArraySize(mScratchTextures); i++)
994     {
995         if (mScratchTextures[i] == 0)
996         {
997             ANGLE_GL_TRY(context, mFunctions->genTextures(1, &mScratchTextures[i]));
998         }
999     }
1000
1001     if (mScratchFBO == 0)
1002     {
1003         ANGLE_GL_TRY(context, mFunctions->genFramebuffers(1, &mScratchFBO));
1004     }
1005
1006     if (mVertexBuffer == 0)
1007     {
1008         ANGLE_GL_TRY(context, mFunctions->genBuffers(1, &mVertexBuffer));
1009         mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
1010
1011         // Use a single, large triangle, to avoid arithmetic precision issues where fragments
1012         // with the same Y coordinate don't get exactly the same interpolated texcoord Y.
1013         float vertexData[] = {
1014             -0.5f, 0.0f, 1.5f, 0.0f, 0.5f, 2.0f,
1015         };
1016
1017         ANGLE_GL_TRY(context, mFunctions->bufferData(GL_ARRAY_BUFFER, sizeof(float) * 6, vertexData,
1018                                                      GL_STATIC_DRAW));
1019     }
1020
1021     if (mVAO == 0)
1022     {
1023         ANGLE_GL_TRY(context, mFunctions->genVertexArrays(1, &mVAO));
1024
1025         mStateManager->bindVertexArray(mVAO, 0);
1026         mStateManager->bindBuffer(gl::BufferBinding::Array, mVertexBuffer);
1027
1028         // Enable all attributes with the same buffer so that it doesn't matter what location the
1029         // texcoord attribute is assigned
1030         GLint maxAttributes = 0;
1031         ANGLE_GL_TRY(context, mFunctions->getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttributes));
1032
1033         for (GLint i = 0; i < maxAttributes; i++)
1034         {
1035             ANGLE_GL_TRY(context, mFunctions->enableVertexAttribArray(i));
1036             ANGLE_GL_TRY(context,
1037                          mFunctions->vertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
1038         }
1039     }
1040
1041     return angle::Result::Continue;
1042 }
1043
1044 angle::Result BlitGL::orphanScratchTextures(const gl::Context *context)
1045 {
1046     for (auto texture : mScratchTextures)
1047     {
1048         mStateManager->bindTexture(gl::TextureType::_2D, texture);
1049         gl::PixelUnpackState unpack;
1050         mStateManager->setPixelUnpackState(unpack);
1051         mStateManager->setPixelUnpackBuffer(nullptr);
1052         GLint swizzle[4] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
1053         ANGLE_GL_TRY(context,
1054                      mFunctions->texParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1055         ANGLE_GL_TRY(context, mFunctions->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, GL_RGBA,
1056                                                      GL_UNSIGNED_BYTE, nullptr));
1057     }
1058     return angle::Result::Continue;
1059 }
1060
1061 angle::Result BlitGL::setScratchTextureParameter(const gl::Context *context,
1062                                                  GLenum param,
1063                                                  GLenum value)
1064 {
1065     for (auto texture : mScratchTextures)
1066     {
1067         mStateManager->bindTexture(gl::TextureType::_2D, texture);
1068         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, param, value));
1069         ANGLE_GL_TRY(context, mFunctions->texParameteri(GL_TEXTURE_2D, param, value));
1070     }
1071     return angle::Result::Continue;
1072 }
1073
1074 angle::Result BlitGL::getBlitProgram(const gl::Context *context,
1075                                      gl::TextureType sourceTextureType,
1076                                      GLenum sourceComponentType,
1077                                      GLenum destComponentType,
1078                                      BlitProgram **program)
1079 {
1080
1081     BlitProgramType programType(sourceTextureType, sourceComponentType, destComponentType);
1082     BlitProgram &result = mBlitPrograms[programType];
1083     if (result.program == 0)
1084     {
1085         result.program = ANGLE_GL_TRY(context, mFunctions->createProgram());
1086
1087         // Depending on what types need to be output by the shaders, different versions need to be
1088         // used.
1089         std::string version;
1090         std::string vsInputVariableQualifier;
1091         std::string vsOutputVariableQualifier;
1092         std::string fsInputVariableQualifier;
1093         std::string fsOutputVariableQualifier;
1094         std::string sampleFunction;
1095         if (sourceComponentType != GL_UNSIGNED_INT && destComponentType != GL_UNSIGNED_INT &&
1096             sourceTextureType != gl::TextureType::Rectangle)
1097         {
1098             // Simple case, float-to-float with 2D or external textures.  Only needs ESSL/GLSL 100
1099             version                   = "100";
1100             vsInputVariableQualifier  = "attribute";
1101             vsOutputVariableQualifier = "varying";
1102             fsInputVariableQualifier  = "varying";
1103             fsOutputVariableQualifier = "";
1104             sampleFunction            = "texture2D";
1105         }
1106         else
1107         {
1108             // Need to use a higher version to support non-float output types
1109             if (mFunctions->standard == STANDARD_GL_DESKTOP)
1110             {
1111                 version = "330";
1112             }
1113             else
1114             {
1115                 ASSERT(mFunctions->standard == STANDARD_GL_ES);
1116                 version = "300 es";
1117             }
1118             vsInputVariableQualifier  = "in";
1119             vsOutputVariableQualifier = "out";
1120             fsInputVariableQualifier  = "in";
1121             fsOutputVariableQualifier = "out";
1122             sampleFunction            = "texture";
1123         }
1124
1125         {
1126             // Compile the vertex shader
1127             std::ostringstream vsSourceStream;
1128             vsSourceStream << "#version " << version << "\n";
1129             vsSourceStream << vsInputVariableQualifier << " vec2 a_texcoord;\n";
1130             vsSourceStream << "uniform vec2 u_scale;\n";
1131             vsSourceStream << "uniform vec2 u_offset;\n";
1132             vsSourceStream << vsOutputVariableQualifier << " vec2 v_texcoord;\n";
1133             vsSourceStream << "\n";
1134             vsSourceStream << "void main()\n";
1135             vsSourceStream << "{\n";
1136             vsSourceStream << "    gl_Position = vec4((a_texcoord * 2.0) - 1.0, 0.0, 1.0);\n";
1137             vsSourceStream << "    v_texcoord = a_texcoord * u_scale + u_offset;\n";
1138             vsSourceStream << "}\n";
1139
1140             std::string vsSourceStr  = vsSourceStream.str();
1141             const char *vsSourceCStr = vsSourceStr.c_str();
1142
1143             GLuint vs = ANGLE_GL_TRY(context, mFunctions->createShader(GL_VERTEX_SHADER));
1144             ANGLE_GL_TRY(context, mFunctions->shaderSource(vs, 1, &vsSourceCStr, nullptr));
1145             ANGLE_GL_TRY(context, mFunctions->compileShader(vs));
1146             ANGLE_TRY(CheckCompileStatus(context, mFunctions, vs));
1147
1148             ANGLE_GL_TRY(context, mFunctions->attachShader(result.program, vs));
1149             ANGLE_GL_TRY(context, mFunctions->deleteShader(vs));
1150         }
1151
1152         {
1153             // Sampling texture uniform changes depending on source texture type.
1154             std::string samplerType;
1155             switch (sourceTextureType)
1156             {
1157                 case gl::TextureType::_2D:
1158                     switch (sourceComponentType)
1159                     {
1160                         case GL_UNSIGNED_INT:
1161                             samplerType = "usampler2D";
1162                             break;
1163
1164                         default:  // Float type
1165                             samplerType = "sampler2D";
1166                             break;
1167                     }
1168                     break;
1169
1170                 case gl::TextureType::External:
1171                     ASSERT(sourceComponentType != GL_UNSIGNED_INT);
1172                     samplerType = "samplerExternalOES";
1173                     break;
1174
1175                 case gl::TextureType::Rectangle:
1176                     ASSERT(sourceComponentType != GL_UNSIGNED_INT);
1177                     samplerType = "sampler2DRect";
1178                     break;
1179
1180                 default:
1181                     UNREACHABLE();
1182                     break;
1183             }
1184
1185             std::string samplerResultType;
1186             switch (sourceComponentType)
1187             {
1188                 case GL_UNSIGNED_INT:
1189                     samplerResultType = "uvec4";
1190                     break;
1191
1192                 default:  // Float type
1193                     samplerResultType = "vec4";
1194                     break;
1195             }
1196
1197             std::string extensionRequirements;
1198             switch (sourceTextureType)
1199             {
1200                 case gl::TextureType::External:
1201                     extensionRequirements = "#extension GL_OES_EGL_image_external : require";
1202                     break;
1203
1204                 case gl::TextureType::Rectangle:
1205                     if (mFunctions->hasGLExtension("GL_ARB_texture_rectangle"))
1206                     {
1207                         extensionRequirements = "#extension GL_ARB_texture_rectangle : require";
1208                     }
1209                     else
1210                     {
1211                         ASSERT(mFunctions->isAtLeastGL(gl::Version(3, 1)));
1212                     }
1213                     break;
1214
1215                 default:
1216                     break;
1217             }
1218
1219             // Output variables depend on the output type
1220             std::string outputType;
1221             std::string outputVariableName;
1222             std::string outputMultiplier;
1223             switch (destComponentType)
1224             {
1225                 case GL_UNSIGNED_INT:
1226                     outputType         = "uvec4";
1227                     outputVariableName = "outputUint";
1228                     outputMultiplier   = "255.0";
1229                     break;
1230
1231                 default:  //  float type
1232                     if (version == "100")
1233                     {
1234                         outputType         = "";
1235                         outputVariableName = "gl_FragColor";
1236                         outputMultiplier   = "1.0";
1237                     }
1238                     else
1239                     {
1240                         outputType         = "vec4";
1241                         outputVariableName = "outputFloat";
1242                         outputMultiplier   = "1.0";
1243                     }
1244                     break;
1245             }
1246
1247             // Compile the fragment shader
1248             std::ostringstream fsSourceStream;
1249             fsSourceStream << "#version " << version << "\n";
1250             fsSourceStream << extensionRequirements << "\n";
1251             fsSourceStream << "precision highp float;\n";
1252             fsSourceStream << "uniform " << samplerType << " u_source_texture;\n";
1253
1254             // Write the rest of the uniforms and varyings
1255             fsSourceStream << "uniform bool u_multiply_alpha;\n";
1256             fsSourceStream << "uniform bool u_unmultiply_alpha;\n";
1257             fsSourceStream << fsInputVariableQualifier << " vec2 v_texcoord;\n";
1258             if (!outputType.empty())
1259             {
1260                 fsSourceStream << fsOutputVariableQualifier << " " << outputType << " "
1261                                << outputVariableName << ";\n";
1262             }
1263
1264             // Write the main body
1265             fsSourceStream << "\n";
1266             fsSourceStream << "void main()\n";
1267             fsSourceStream << "{\n";
1268
1269             std::string maxTexcoord;
1270             switch (sourceTextureType)
1271             {
1272                 case gl::TextureType::Rectangle:
1273                     // Valid texcoords are within source texture size
1274                     maxTexcoord = "vec2(textureSize(u_source_texture))";
1275                     break;
1276
1277                 default:
1278                     // Valid texcoords are in [0, 1]
1279                     maxTexcoord = "vec2(1.0)";
1280                     break;
1281             }
1282
1283             // discard if the texcoord is invalid so the blitframebuffer workaround doesn't
1284             // write when the point sampled is outside of the source framebuffer.
1285             fsSourceStream << "    if (clamp(v_texcoord, vec2(0.0), " << maxTexcoord
1286                            << ") != v_texcoord)\n";
1287             fsSourceStream << "    {\n";
1288             fsSourceStream << "        discard;\n";
1289             fsSourceStream << "    }\n";
1290
1291             // Sampling code depends on the input data type
1292             fsSourceStream << "    " << samplerResultType << " color = " << sampleFunction
1293                            << "(u_source_texture, v_texcoord);\n";
1294
1295             // Perform the premultiply or unmultiply alpha logic
1296             fsSourceStream << "    if (u_multiply_alpha)\n";
1297             fsSourceStream << "    {\n";
1298             fsSourceStream << "        color.xyz = color.xyz * color.a;\n";
1299             fsSourceStream << "    }\n";
1300             fsSourceStream << "    if (u_unmultiply_alpha && color.a != 0.0)\n";
1301             fsSourceStream << "    {\n";
1302             fsSourceStream << "         color.xyz = color.xyz / color.a;\n";
1303             fsSourceStream << "    }\n";
1304
1305             // Write the conversion to the destionation type
1306             fsSourceStream << "    color = color * " << outputMultiplier << ";\n";
1307
1308             // Write the output assignment code
1309             fsSourceStream << "    " << outputVariableName << " = " << outputType << "(color);\n";
1310             fsSourceStream << "}\n";
1311
1312             std::string fsSourceStr  = fsSourceStream.str();
1313             const char *fsSourceCStr = fsSourceStr.c_str();
1314
1315             GLuint fs = ANGLE_GL_TRY(context, mFunctions->createShader(GL_FRAGMENT_SHADER));
1316             ANGLE_GL_TRY(context, mFunctions->shaderSource(fs, 1, &fsSourceCStr, nullptr));
1317             ANGLE_GL_TRY(context, mFunctions->compileShader(fs));
1318             ANGLE_TRY(CheckCompileStatus(context, mFunctions, fs));
1319
1320             ANGLE_GL_TRY(context, mFunctions->attachShader(result.program, fs));
1321             ANGLE_GL_TRY(context, mFunctions->deleteShader(fs));
1322         }
1323
1324         ANGLE_GL_TRY(context, mFunctions->linkProgram(result.program));
1325         ANGLE_TRY(CheckLinkStatus(context, mFunctions, result.program));
1326
1327         result.sourceTextureLocation = ANGLE_GL_TRY(
1328             context, mFunctions->getUniformLocation(result.program, "u_source_texture"));
1329         result.scaleLocation =
1330             ANGLE_GL_TRY(context, mFunctions->getUniformLocation(result.program, "u_scale"));
1331         result.offsetLocation =
1332             ANGLE_GL_TRY(context, mFunctions->getUniformLocation(result.program, "u_offset"));
1333         result.multiplyAlphaLocation = ANGLE_GL_TRY(
1334             context, mFunctions->getUniformLocation(result.program, "u_multiply_alpha"));
1335         result.unMultiplyAlphaLocation = ANGLE_GL_TRY(
1336             context, mFunctions->getUniformLocation(result.program, "u_unmultiply_alpha"));
1337     }
1338
1339     *program = &result;
1340     return angle::Result::Continue;
1341 }
1342
1343 }  // namespace rx