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