• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // TextureGL.cpp: Implements the class methods for TextureGL.
8 
9 #include "libANGLE/renderer/gl/TextureGL.h"
10 
11 #include "common/bitset_utils.h"
12 #include "common/debug.h"
13 #include "common/utilities.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/MemoryObject.h"
16 #include "libANGLE/State.h"
17 #include "libANGLE/Surface.h"
18 #include "libANGLE/angletypes.h"
19 #include "libANGLE/formatutils.h"
20 #include "libANGLE/queryconversions.h"
21 #include "libANGLE/renderer/gl/BlitGL.h"
22 #include "libANGLE/renderer/gl/BufferGL.h"
23 #include "libANGLE/renderer/gl/ContextGL.h"
24 #include "libANGLE/renderer/gl/FramebufferGL.h"
25 #include "libANGLE/renderer/gl/FunctionsGL.h"
26 #include "libANGLE/renderer/gl/ImageGL.h"
27 #include "libANGLE/renderer/gl/MemoryObjectGL.h"
28 #include "libANGLE/renderer/gl/StateManagerGL.h"
29 #include "libANGLE/renderer/gl/SurfaceGL.h"
30 #include "libANGLE/renderer/gl/formatutilsgl.h"
31 #include "libANGLE/renderer/gl/renderergl_utils.h"
32 #include "platform/autogen/FeaturesGL_autogen.h"
33 
34 using angle::CheckedNumeric;
35 
36 namespace rx
37 {
38 
39 namespace
40 {
41 // For use with the uploadTextureDataInChunks feature.  See http://crbug.com/1181068
42 constexpr const size_t kUploadTextureDataInChunksUploadSize = (120 * 1024) - 1;
43 
GetLevelInfoIndex(gl::TextureTarget target,size_t level)44 size_t GetLevelInfoIndex(gl::TextureTarget target, size_t level)
45 {
46     return gl::IsCubeMapFaceTarget(target)
47                ? ((level * gl::kCubeFaceCount) + gl::CubeMapTextureTargetToFaceIndex(target))
48                : level;
49 }
50 
IsLUMAFormat(GLenum format)51 bool IsLUMAFormat(GLenum format)
52 {
53     return format == GL_LUMINANCE || format == GL_ALPHA || format == GL_LUMINANCE_ALPHA;
54 }
55 
GetLUMAWorkaroundInfo(GLenum originalFormat,GLenum destinationFormat)56 LUMAWorkaroundGL GetLUMAWorkaroundInfo(GLenum originalFormat, GLenum destinationFormat)
57 {
58     if (IsLUMAFormat(originalFormat))
59     {
60         return LUMAWorkaroundGL(!IsLUMAFormat(destinationFormat), destinationFormat);
61     }
62     else
63     {
64         return LUMAWorkaroundGL(false, GL_NONE);
65     }
66 }
67 
GetDepthStencilWorkaround(GLenum format)68 bool GetDepthStencilWorkaround(GLenum format)
69 {
70     return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL;
71 }
72 
GetEmulatedAlphaChannel(const angle::FeaturesGL & features,const gl::InternalFormat & originalInternalFormat)73 bool GetEmulatedAlphaChannel(const angle::FeaturesGL &features,
74                              const gl::InternalFormat &originalInternalFormat)
75 {
76     return (features.RGBDXT1TexturesSampleZeroAlpha.enabled &&
77             (originalInternalFormat.sizedInternalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
78              originalInternalFormat.sizedInternalFormat == GL_COMPRESSED_SRGB_S3TC_DXT1_EXT)) ||
79            (features.emulateRGB10.enabled && originalInternalFormat.format == GL_RGB &&
80             originalInternalFormat.type == GL_UNSIGNED_INT_2_10_10_10_REV_EXT);
81 }
82 
GetLevelInfo(const angle::FeaturesGL & features,const gl::InternalFormat & originalInternalFormat,GLenum destinationInternalFormat)83 LevelInfoGL GetLevelInfo(const angle::FeaturesGL &features,
84                          const gl::InternalFormat &originalInternalFormat,
85                          GLenum destinationInternalFormat)
86 {
87     GLenum destinationFormat = gl::GetUnsizedFormat(destinationInternalFormat);
88     return LevelInfoGL(originalInternalFormat.format, destinationInternalFormat,
89                        GetDepthStencilWorkaround(originalInternalFormat.format),
90                        GetLUMAWorkaroundInfo(originalInternalFormat.format, destinationFormat),
91                        GetEmulatedAlphaChannel(features, originalInternalFormat));
92 }
93 
GetLevelWorkaroundDirtyBits()94 gl::Texture::DirtyBits GetLevelWorkaroundDirtyBits()
95 {
96     gl::Texture::DirtyBits bits;
97     bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
98     bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
99     bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
100     bits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
101     return bits;
102 }
103 
GetMaxLevelInfoCountForTextureType(gl::TextureType type)104 size_t GetMaxLevelInfoCountForTextureType(gl::TextureType type)
105 {
106     switch (type)
107     {
108         case gl::TextureType::CubeMap:
109             return (gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * gl::kCubeFaceCount;
110 
111         case gl::TextureType::External:
112             return 1;
113 
114         default:
115             return gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1;
116     }
117 }
118 
119 }  // anonymous namespace
120 
LUMAWorkaroundGL()121 LUMAWorkaroundGL::LUMAWorkaroundGL() : LUMAWorkaroundGL(false, GL_NONE) {}
122 
LUMAWorkaroundGL(bool enabled_,GLenum workaroundFormat_)123 LUMAWorkaroundGL::LUMAWorkaroundGL(bool enabled_, GLenum workaroundFormat_)
124     : enabled(enabled_), workaroundFormat(workaroundFormat_)
125 {}
126 
LevelInfoGL()127 LevelInfoGL::LevelInfoGL() : LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(), false) {}
128 
LevelInfoGL(GLenum sourceFormat_,GLenum nativeInternalFormat_,bool depthStencilWorkaround_,const LUMAWorkaroundGL & lumaWorkaround_,bool emulatedAlphaChannel_)129 LevelInfoGL::LevelInfoGL(GLenum sourceFormat_,
130                          GLenum nativeInternalFormat_,
131                          bool depthStencilWorkaround_,
132                          const LUMAWorkaroundGL &lumaWorkaround_,
133                          bool emulatedAlphaChannel_)
134     : sourceFormat(sourceFormat_),
135       nativeInternalFormat(nativeInternalFormat_),
136       depthStencilWorkaround(depthStencilWorkaround_),
137       lumaWorkaround(lumaWorkaround_),
138       emulatedAlphaChannel(emulatedAlphaChannel_)
139 {}
140 
TextureGL(const gl::TextureState & state,GLuint id)141 TextureGL::TextureGL(const gl::TextureState &state, GLuint id)
142     : TextureImpl(state),
143       mAppliedSwizzle(state.getSwizzleState()),
144       mAppliedSampler(state.getSamplerState()),
145       mAppliedBaseLevel(state.getEffectiveBaseLevel()),
146       mAppliedMaxLevel(state.getEffectiveMaxLevel()),
147       mTextureID(id)
148 {
149     mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
150 }
151 
~TextureGL()152 TextureGL::~TextureGL()
153 {
154     ASSERT(mTextureID == 0);
155 }
156 
onDestroy(const gl::Context * context)157 void TextureGL::onDestroy(const gl::Context *context)
158 {
159     GetImplAs<ContextGL>(context)->flushIfNecessaryBeforeDeleteTextures();
160     StateManagerGL *stateManager = GetStateManagerGL(context);
161     stateManager->deleteTexture(mTextureID);
162     mTextureID = 0;
163 }
164 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)165 angle::Result TextureGL::setImage(const gl::Context *context,
166                                   const gl::ImageIndex &index,
167                                   GLenum internalFormat,
168                                   const gl::Extents &size,
169                                   GLenum format,
170                                   GLenum type,
171                                   const gl::PixelUnpackState &unpack,
172                                   gl::Buffer *unpackBuffer,
173                                   const uint8_t *pixels)
174 {
175     const angle::FeaturesGL &features = GetFeaturesGL(context);
176 
177     gl::TextureTarget target = index.getTarget();
178     size_t level             = static_cast<size_t>(index.getLevelIndex());
179 
180     if (features.unpackOverlappingRowsSeparatelyUnpackBuffer.enabled && unpackBuffer &&
181         unpack.rowLength != 0 && unpack.rowLength < size.width)
182     {
183         // The rows overlap in unpack memory. Upload the texture row by row to work around
184         // driver bug.
185         ANGLE_TRY(
186             reserveTexImageToBeFilled(context, target, level, internalFormat, size, format, type));
187 
188         if (size.width == 0 || size.height == 0 || size.depth == 0)
189         {
190             return angle::Result::Continue;
191         }
192 
193         gl::Box area(0, 0, 0, size.width, size.height, size.depth);
194         return setSubImageRowByRowWorkaround(context, target, level, area, format, type, unpack,
195                                              unpackBuffer, 0, pixels);
196     }
197 
198     if (features.unpackLastRowSeparatelyForPaddingInclusion.enabled)
199     {
200         bool apply = false;
201         ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
202             GetImplAs<ContextGL>(context), size, unpack, unpackBuffer, format, type,
203             nativegl::UseTexImage3D(getType()), pixels, &apply));
204 
205         // The driver will think the pixel buffer doesn't have enough data, work around this bug
206         // by uploading the last row (and last level if 3D) separately.
207         if (apply)
208         {
209             ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat, size,
210                                                 format, type));
211 
212             if (size.width == 0 || size.height == 0 || size.depth == 0)
213             {
214                 return angle::Result::Continue;
215             }
216 
217             gl::Box area(0, 0, 0, size.width, size.height, size.depth);
218             return setSubImagePaddingWorkaround(context, target, level, area, format, type, unpack,
219                                                 unpackBuffer, pixels);
220         }
221     }
222 
223     ANGLE_TRY(setImageHelper(context, target, level, internalFormat, size, format, type, pixels));
224 
225     return angle::Result::Continue;
226 }
227 
setImageHelper(const gl::Context * context,gl::TextureTarget target,size_t level,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const uint8_t * pixels)228 angle::Result TextureGL::setImageHelper(const gl::Context *context,
229                                         gl::TextureTarget target,
230                                         size_t level,
231                                         GLenum internalFormat,
232                                         const gl::Extents &size,
233                                         GLenum format,
234                                         GLenum type,
235                                         const uint8_t *pixels)
236 {
237     ASSERT(TextureTargetToType(target) == getType());
238 
239     const FunctionsGL *functions      = GetFunctionsGL(context);
240     StateManagerGL *stateManager      = GetStateManagerGL(context);
241     const angle::FeaturesGL &features = GetFeaturesGL(context);
242 
243     const gl::InternalFormat &originalInternalFormatInfo =
244         gl::GetInternalFormatInfo(internalFormat, type);
245     nativegl::TexImageFormat texImageFormat =
246         nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
247 
248     stateManager->bindTexture(getType(), mTextureID);
249 
250     if (features.resetTexImage2DBaseLevel.enabled)
251     {
252         // setBaseLevel doesn't ever generate errors.
253         (void)setBaseLevel(context, 0);
254     }
255 
256     if (nativegl::UseTexImage2D(getType()))
257     {
258         ASSERT(size.depth == 1);
259         ANGLE_GL_TRY_ALWAYS_CHECK(
260             context, functions->texImage2D(nativegl::GetTextureBindingTarget(target),
261                                            static_cast<GLint>(level), texImageFormat.internalFormat,
262                                            size.width, size.height, 0, texImageFormat.format,
263                                            texImageFormat.type, pixels));
264     }
265     else
266     {
267         ASSERT(nativegl::UseTexImage3D(getType()));
268         ANGLE_GL_TRY_ALWAYS_CHECK(
269             context, functions->texImage3D(ToGLenum(target), static_cast<GLint>(level),
270                                            texImageFormat.internalFormat, size.width, size.height,
271                                            size.depth, 0, texImageFormat.format,
272                                            texImageFormat.type, pixels));
273     }
274 
275     LevelInfoGL levelInfo =
276         GetLevelInfo(features, originalInternalFormatInfo, texImageFormat.internalFormat);
277     setLevelInfo(context, target, level, 1, levelInfo);
278 
279     if (features.setZeroLevelBeforeGenerateMipmap.enabled && getType() == gl::TextureType::_2D &&
280         level != 0 && mLevelInfo[0].nativeInternalFormat == GL_NONE)
281     {
282         // Only fill level zero if it's possible that mipmaps can be generated with this format
283         const gl::InternalFormat &internalFormatInfo =
284             gl::GetInternalFormatInfo(internalFormat, type);
285         if (!internalFormatInfo.sized ||
286             (internalFormatInfo.filterSupport(context->getClientVersion(),
287                                               context->getExtensions()) &&
288              internalFormatInfo.textureAttachmentSupport(context->getClientVersion(),
289                                                          context->getExtensions())))
290         {
291             ANGLE_GL_TRY_ALWAYS_CHECK(
292                 context,
293                 functions->texImage2D(nativegl::GetTextureBindingTarget(target), 0,
294                                       texImageFormat.internalFormat, 1, 1, 0, texImageFormat.format,
295                                       texImageFormat.type, nullptr));
296             setLevelInfo(context, target, 0, 1, levelInfo);
297         }
298     }
299 
300     return angle::Result::Continue;
301 }
302 
reserveTexImageToBeFilled(const gl::Context * context,gl::TextureTarget target,size_t level,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)303 angle::Result TextureGL::reserveTexImageToBeFilled(const gl::Context *context,
304                                                    gl::TextureTarget target,
305                                                    size_t level,
306                                                    GLenum internalFormat,
307                                                    const gl::Extents &size,
308                                                    GLenum format,
309                                                    GLenum type)
310 {
311     StateManagerGL *stateManager = GetStateManagerGL(context);
312     ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, nullptr));
313     ANGLE_TRY(setImageHelper(context, target, level, internalFormat, size, format, type, nullptr));
314     return angle::Result::Continue;
315 }
316 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)317 angle::Result TextureGL::setSubImage(const gl::Context *context,
318                                      const gl::ImageIndex &index,
319                                      const gl::Box &area,
320                                      GLenum format,
321                                      GLenum type,
322                                      const gl::PixelUnpackState &unpack,
323                                      gl::Buffer *unpackBuffer,
324                                      const uint8_t *pixels)
325 {
326     ASSERT(TextureTargetToType(index.getTarget()) == getType());
327 
328     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
329     const FunctionsGL *functions      = GetFunctionsGL(context);
330     StateManagerGL *stateManager      = GetStateManagerGL(context);
331     const angle::FeaturesGL &features = GetFeaturesGL(context);
332 
333     const gl::InternalFormat &originalInternalFormatInfo = *mState.getImageDesc(index).format.info;
334     nativegl::TexSubImageFormat texSubImageFormat =
335         nativegl::GetTexSubImageFormat(functions, features, format, type);
336 
337     gl::TextureTarget target = index.getTarget();
338     size_t level             = static_cast<size_t>(index.getLevelIndex());
339 
340     ASSERT(getLevelInfo(target, level).lumaWorkaround.enabled ==
341            GetLevelInfo(features, originalInternalFormatInfo, texSubImageFormat.format)
342                .lumaWorkaround.enabled);
343 
344     stateManager->bindTexture(getType(), mTextureID);
345     if (features.unpackOverlappingRowsSeparatelyUnpackBuffer.enabled && unpackBuffer &&
346         unpack.rowLength != 0 && unpack.rowLength < area.width)
347     {
348         ANGLE_TRY(setSubImageRowByRowWorkaround(context, target, level, area, format, type, unpack,
349                                                 unpackBuffer, 0, pixels));
350         contextGL->markWorkSubmitted();
351         return angle::Result::Continue;
352     }
353 
354     if (features.unpackLastRowSeparatelyForPaddingInclusion.enabled)
355     {
356         gl::Extents size(area.width, area.height, area.depth);
357 
358         bool apply = false;
359         ANGLE_TRY(ShouldApplyLastRowPaddingWorkaround(
360             GetImplAs<ContextGL>(context), size, unpack, unpackBuffer, format, type,
361             nativegl::UseTexImage3D(getType()), pixels, &apply));
362 
363         // The driver will think the pixel buffer doesn't have enough data, work around this bug
364         // by uploading the last row (and last level if 3D) separately.
365         if (apply)
366         {
367             ANGLE_TRY(setSubImagePaddingWorkaround(context, target, level, area, format, type,
368                                                    unpack, unpackBuffer, pixels));
369             contextGL->markWorkSubmitted();
370             return angle::Result::Continue;
371         }
372     }
373 
374     if (features.uploadTextureDataInChunks.enabled)
375     {
376         ANGLE_TRY(setSubImageRowByRowWorkaround(context, target, level, area, format, type, unpack,
377                                                 unpackBuffer, kUploadTextureDataInChunksUploadSize,
378                                                 pixels));
379         contextGL->markWorkSubmitted();
380         return angle::Result::Continue;
381     }
382 
383     if (nativegl::UseTexImage2D(getType()))
384     {
385         ASSERT(area.z == 0 && area.depth == 1);
386         ANGLE_GL_TRY(context,
387                      functions->texSubImage2D(nativegl::GetTextureBindingTarget(target),
388                                               static_cast<GLint>(level), area.x, area.y, area.width,
389                                               area.height, texSubImageFormat.format,
390                                               texSubImageFormat.type, pixels));
391     }
392     else
393     {
394         ASSERT(nativegl::UseTexImage3D(getType()));
395         ANGLE_GL_TRY(context, functions->texSubImage3D(
396                                   ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
397                                   area.z, area.width, area.height, area.depth,
398                                   texSubImageFormat.format, texSubImageFormat.type, pixels));
399     }
400 
401     contextGL->markWorkSubmitted();
402     return angle::Result::Continue;
403 }
404 
setSubImageRowByRowWorkaround(const gl::Context * context,gl::TextureTarget target,size_t level,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,const gl::Buffer * unpackBuffer,size_t maxBytesUploadedPerChunk,const uint8_t * pixels)405 angle::Result TextureGL::setSubImageRowByRowWorkaround(const gl::Context *context,
406                                                        gl::TextureTarget target,
407                                                        size_t level,
408                                                        const gl::Box &area,
409                                                        GLenum format,
410                                                        GLenum type,
411                                                        const gl::PixelUnpackState &unpack,
412                                                        const gl::Buffer *unpackBuffer,
413                                                        size_t maxBytesUploadedPerChunk,
414                                                        const uint8_t *pixels)
415 {
416     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
417     const FunctionsGL *functions      = GetFunctionsGL(context);
418     StateManagerGL *stateManager      = GetStateManagerGL(context);
419     const angle::FeaturesGL &features = GetFeaturesGL(context);
420 
421     gl::PixelUnpackState directUnpack = unpack;
422     directUnpack.skipRows             = 0;
423     directUnpack.skipPixels           = 0;
424     directUnpack.skipImages           = 0;
425     ANGLE_TRY(stateManager->setPixelUnpackState(context, directUnpack));
426     ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, unpackBuffer));
427 
428     const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
429     GLuint rowBytes                    = 0;
430     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, unpack.alignment,
431                                                             unpack.rowLength, &rowBytes));
432     GLuint imageBytes = 0;
433     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeDepthPitch(area.height, unpack.imageHeight,
434                                                               rowBytes, &imageBytes));
435 
436     bool useTexImage3D = nativegl::UseTexImage3D(getType());
437     GLuint skipBytes   = 0;
438     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeSkipBytes(type, rowBytes, imageBytes, unpack,
439                                                              useTexImage3D, &skipBytes));
440 
441     GLint rowsPerChunk =
442         std::min(std::max(static_cast<GLint>(maxBytesUploadedPerChunk / rowBytes), 1), area.height);
443     if (maxBytesUploadedPerChunk > 0 && rowsPerChunk < area.height)
444     {
445         ANGLE_PERF_WARNING(contextGL->getDebug(), GL_DEBUG_SEVERITY_LOW,
446                            "Chunking upload of texture data to work around driver hangs.");
447     }
448 
449     nativegl::TexSubImageFormat texSubImageFormat =
450         nativegl::GetTexSubImageFormat(functions, features, format, type);
451 
452     const uint8_t *pixelsWithSkip = pixels + skipBytes;
453     if (useTexImage3D)
454     {
455         for (GLint image = 0; image < area.depth; ++image)
456         {
457             GLint imageByteOffset = image * imageBytes;
458             for (GLint row = 0; row < area.height; row += rowsPerChunk)
459             {
460                 GLint height             = std::min(rowsPerChunk, area.height - row);
461                 GLint byteOffset         = imageByteOffset + row * rowBytes;
462                 const GLubyte *rowPixels = pixelsWithSkip + byteOffset;
463                 ANGLE_GL_TRY(context,
464                              functions->texSubImage3D(
465                                  ToGLenum(target), static_cast<GLint>(level), area.x, row + area.y,
466                                  image + area.z, area.width, height, 1, texSubImageFormat.format,
467                                  texSubImageFormat.type, rowPixels));
468             }
469         }
470     }
471     else
472     {
473         ASSERT(nativegl::UseTexImage2D(getType()));
474         for (GLint row = 0; row < area.height; row += rowsPerChunk)
475         {
476             GLint height             = std::min(rowsPerChunk, area.height - row);
477             GLint byteOffset         = row * rowBytes;
478             const GLubyte *rowPixels = pixelsWithSkip + byteOffset;
479             ANGLE_GL_TRY(context, functions->texSubImage2D(
480                                       ToGLenum(target), static_cast<GLint>(level), area.x,
481                                       row + area.y, area.width, height, texSubImageFormat.format,
482                                       texSubImageFormat.type, rowPixels));
483         }
484     }
485     return angle::Result::Continue;
486 }
487 
setSubImagePaddingWorkaround(const gl::Context * context,gl::TextureTarget target,size_t level,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,const gl::Buffer * unpackBuffer,const uint8_t * pixels)488 angle::Result TextureGL::setSubImagePaddingWorkaround(const gl::Context *context,
489                                                       gl::TextureTarget target,
490                                                       size_t level,
491                                                       const gl::Box &area,
492                                                       GLenum format,
493                                                       GLenum type,
494                                                       const gl::PixelUnpackState &unpack,
495                                                       const gl::Buffer *unpackBuffer,
496                                                       const uint8_t *pixels)
497 {
498     ContextGL *contextGL         = GetImplAs<ContextGL>(context);
499     const FunctionsGL *functions = GetFunctionsGL(context);
500     StateManagerGL *stateManager = GetStateManagerGL(context);
501 
502     const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(format, type);
503     GLuint rowBytes                    = 0;
504     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeRowPitch(type, area.width, unpack.alignment,
505                                                             unpack.rowLength, &rowBytes));
506     GLuint imageBytes = 0;
507     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeDepthPitch(area.height, unpack.imageHeight,
508                                                               rowBytes, &imageBytes));
509     bool useTexImage3D = nativegl::UseTexImage3D(getType());
510     GLuint skipBytes   = 0;
511     ANGLE_CHECK_GL_MATH(contextGL, glFormat.computeSkipBytes(type, rowBytes, imageBytes, unpack,
512                                                              useTexImage3D, &skipBytes));
513 
514     ANGLE_TRY(stateManager->setPixelUnpackState(context, unpack));
515     ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, unpackBuffer));
516 
517     gl::PixelUnpackState directUnpack;
518     directUnpack.alignment = 1;
519 
520     if (useTexImage3D)
521     {
522         // Upload all but the last slice
523         if (area.depth > 1)
524         {
525             ANGLE_GL_TRY(context,
526                          functions->texSubImage3D(ToGLenum(target), static_cast<GLint>(level),
527                                                   area.x, area.y, area.z, area.width, area.height,
528                                                   area.depth - 1, format, type, pixels));
529         }
530 
531         // Upload the last slice but its last row
532         if (area.height > 1)
533         {
534             // Do not include skipBytes in the last image pixel start offset as it will be done by
535             // the driver
536             GLint lastImageOffset          = (area.depth - 1) * imageBytes;
537             const GLubyte *lastImagePixels = pixels + lastImageOffset;
538             ANGLE_GL_TRY(context, functions->texSubImage3D(
539                                       ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
540                                       area.z + area.depth - 1, area.width, area.height - 1, 1,
541                                       format, type, lastImagePixels));
542         }
543 
544         // Upload the last row of the last slice "manually"
545         ANGLE_TRY(stateManager->setPixelUnpackState(context, directUnpack));
546 
547         GLint lastRowOffset =
548             skipBytes + (area.depth - 1) * imageBytes + (area.height - 1) * rowBytes;
549         const GLubyte *lastRowPixels = pixels + lastRowOffset;
550         ANGLE_GL_TRY(context,
551                      functions->texSubImage3D(ToGLenum(target), static_cast<GLint>(level), area.x,
552                                               area.y + area.height - 1, area.z + area.depth - 1,
553                                               area.width, 1, 1, format, type, lastRowPixels));
554     }
555     else
556     {
557         ASSERT(nativegl::UseTexImage2D(getType()));
558 
559         // Upload all but the last row
560         if (area.height > 1)
561         {
562             ANGLE_GL_TRY(context, functions->texSubImage2D(
563                                       ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
564                                       area.width, area.height - 1, format, type, pixels));
565         }
566 
567         // Upload the last row "manually"
568         ANGLE_TRY(stateManager->setPixelUnpackState(context, directUnpack));
569 
570         GLint lastRowOffset          = skipBytes + (area.height - 1) * rowBytes;
571         const GLubyte *lastRowPixels = pixels + lastRowOffset;
572         ANGLE_GL_TRY(context, functions->texSubImage2D(ToGLenum(target), static_cast<GLint>(level),
573                                                        area.x, area.y + area.height - 1, area.width,
574                                                        1, format, type, lastRowPixels));
575     }
576 
577     return angle::Result::Continue;
578 }
579 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)580 angle::Result TextureGL::setCompressedImage(const gl::Context *context,
581                                             const gl::ImageIndex &index,
582                                             GLenum internalFormat,
583                                             const gl::Extents &size,
584                                             const gl::PixelUnpackState &unpack,
585                                             size_t imageSize,
586                                             const uint8_t *pixels)
587 {
588     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
589     const FunctionsGL *functions      = GetFunctionsGL(context);
590     StateManagerGL *stateManager      = GetStateManagerGL(context);
591     const angle::FeaturesGL &features = GetFeaturesGL(context);
592 
593     gl::TextureTarget target = index.getTarget();
594     size_t level             = static_cast<size_t>(index.getLevelIndex());
595     ASSERT(TextureTargetToType(target) == getType());
596 
597     const gl::InternalFormat &originalInternalFormatInfo =
598         gl::GetSizedInternalFormatInfo(internalFormat);
599     nativegl::CompressedTexImageFormat compressedTexImageFormat =
600         nativegl::GetCompressedTexImageFormat(functions, features, internalFormat);
601 
602     stateManager->bindTexture(getType(), mTextureID);
603     ANGLE_TRY(stateManager->setPixelUnpackState(context, unpack));
604     if (nativegl::UseTexImage2D(getType()))
605     {
606         ASSERT(size.depth == 1);
607         ANGLE_GL_TRY_ALWAYS_CHECK(
608             context, functions->compressedTexImage2D(ToGLenum(target), static_cast<GLint>(level),
609                                                      compressedTexImageFormat.internalFormat,
610                                                      size.width, size.height, 0,
611                                                      static_cast<GLsizei>(imageSize), pixels));
612     }
613     else
614     {
615         ASSERT(nativegl::UseTexImage3D(getType()));
616 
617         ANGLE_GL_TRY_ALWAYS_CHECK(
618             context, functions->compressedTexImage3D(ToGLenum(target), static_cast<GLint>(level),
619                                                      compressedTexImageFormat.internalFormat,
620                                                      size.width, size.height, size.depth, 0,
621                                                      static_cast<GLsizei>(imageSize), pixels));
622     }
623 
624     LevelInfoGL levelInfo =
625         GetLevelInfo(features, originalInternalFormatInfo, compressedTexImageFormat.internalFormat);
626     ASSERT(!levelInfo.lumaWorkaround.enabled);
627     setLevelInfo(context, target, level, 1, levelInfo);
628 
629     contextGL->markWorkSubmitted();
630     return angle::Result::Continue;
631 }
632 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)633 angle::Result TextureGL::setCompressedSubImage(const gl::Context *context,
634                                                const gl::ImageIndex &index,
635                                                const gl::Box &area,
636                                                GLenum format,
637                                                const gl::PixelUnpackState &unpack,
638                                                size_t imageSize,
639                                                const uint8_t *pixels)
640 {
641     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
642     const FunctionsGL *functions      = GetFunctionsGL(context);
643     StateManagerGL *stateManager      = GetStateManagerGL(context);
644     const angle::FeaturesGL &features = GetFeaturesGL(context);
645 
646     gl::TextureTarget target = index.getTarget();
647     size_t level             = static_cast<size_t>(index.getLevelIndex());
648     ASSERT(TextureTargetToType(target) == getType());
649 
650     const gl::InternalFormat &originalInternalFormatInfo = gl::GetSizedInternalFormatInfo(format);
651     nativegl::CompressedTexSubImageFormat compressedTexSubImageFormat =
652         nativegl::GetCompressedSubTexImageFormat(functions, features, format);
653 
654     stateManager->bindTexture(getType(), mTextureID);
655     if (nativegl::UseTexImage2D(getType()))
656     {
657         ASSERT(area.z == 0 && area.depth == 1);
658         ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
659                                   ToGLenum(target), static_cast<GLint>(level), area.x, area.y,
660                                   area.width, area.height, compressedTexSubImageFormat.format,
661                                   static_cast<GLsizei>(imageSize), pixels));
662     }
663     else
664     {
665         ASSERT(nativegl::UseTexImage3D(getType()));
666         ANGLE_GL_TRY(context,
667                      functions->compressedTexSubImage3D(
668                          ToGLenum(target), static_cast<GLint>(level), area.x, area.y, area.z,
669                          area.width, area.height, area.depth, compressedTexSubImageFormat.format,
670                          static_cast<GLsizei>(imageSize), pixels));
671     }
672 
673     ASSERT(!getLevelInfo(target, level).lumaWorkaround.enabled &&
674            !GetLevelInfo(features, originalInternalFormatInfo, compressedTexSubImageFormat.format)
675                 .lumaWorkaround.enabled);
676 
677     contextGL->markWorkSubmitted();
678     return angle::Result::Continue;
679 }
680 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)681 angle::Result TextureGL::copyImage(const gl::Context *context,
682                                    const gl::ImageIndex &index,
683                                    const gl::Rectangle &sourceArea,
684                                    GLenum internalFormat,
685                                    gl::Framebuffer *source)
686 {
687     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
688     const FunctionsGL *functions      = GetFunctionsGL(context);
689     StateManagerGL *stateManager      = GetStateManagerGL(context);
690     const angle::FeaturesGL &features = GetFeaturesGL(context);
691 
692     gl::TextureTarget target = index.getTarget();
693     size_t level             = static_cast<size_t>(index.getLevelIndex());
694     GLenum type              = source->getImplementationColorReadType(context);
695     const gl::InternalFormat &originalInternalFormatInfo =
696         gl::GetInternalFormatInfo(internalFormat, type);
697     nativegl::CopyTexImageImageFormat copyTexImageFormat =
698         nativegl::GetCopyTexImageImageFormat(functions, features, internalFormat, type);
699 
700     stateManager->bindTexture(getType(), mTextureID);
701 
702     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
703     gl::Extents fbSize = sourceFramebufferGL->getState().getReadAttachment()->getSize();
704 
705     // Did the read area go outside the framebuffer?
706     bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
707                    sourceArea.x + sourceArea.width > fbSize.width ||
708                    sourceArea.y + sourceArea.height > fbSize.height;
709 
710     // TODO: Find a way to initialize the texture entirely in the gl level with ensureInitialized.
711     // Right now there is no easy way to pre-fill the texture when it is being redefined with
712     // partially uninitialized data.
713     bool requiresInitialization =
714         outside && (context->isRobustResourceInitEnabled() || context->isWebGL());
715 
716     // When robust resource initialization is enabled, the area outside the framebuffer must be
717     // zeroed. We just zero the whole thing before copying into the area that overlaps the
718     // framebuffer.
719     if (requiresInitialization)
720     {
721         GLuint pixelBytes =
722             gl::GetInternalFormatInfo(copyTexImageFormat.internalFormat, type).pixelBytes;
723         angle::MemoryBuffer *zero;
724         ANGLE_CHECK_GL_ALLOC(
725             contextGL,
726             context->getZeroFilledBuffer(sourceArea.width * sourceArea.height * pixelBytes, &zero));
727 
728         gl::PixelUnpackState unpack;
729         unpack.alignment = 1;
730         ANGLE_TRY(stateManager->setPixelUnpackState(context, unpack));
731         ANGLE_TRY(stateManager->setPixelUnpackBuffer(context, nullptr));
732 
733         // getImplementationColorReadType aligns the type with ES client version
734         if (type == GL_HALF_FLOAT_OES && functions->standard == STANDARD_GL_DESKTOP)
735         {
736             type = GL_HALF_FLOAT;
737         }
738 
739         ANGLE_GL_TRY_ALWAYS_CHECK(
740             context, functions->texImage2D(ToGLenum(target), static_cast<GLint>(level),
741                                            copyTexImageFormat.internalFormat, sourceArea.width,
742                                            sourceArea.height, 0,
743                                            gl::GetUnsizedFormat(copyTexImageFormat.internalFormat),
744                                            type, zero->data()));
745     }
746 
747     // Clip source area to framebuffer and copy if remaining area is not empty.
748     gl::Rectangle clippedArea;
749     if (ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
750     {
751         // If fbo's read buffer and the target texture are the same texture but different levels,
752         // and if the read buffer is a non-base texture level, then implementations glTexImage2D
753         // may change the target texture and make the original texture mipmap incomplete, which in
754         // turn makes the fbo incomplete.
755         // To avoid that, we clamp BASE_LEVEL and MAX_LEVEL to the same texture level as the fbo's
756         // read buffer attachment. See http://crbug.com/797235
757         const gl::FramebufferAttachment *readBuffer = source->getReadColorAttachment();
758         if (readBuffer && readBuffer->type() == GL_TEXTURE)
759         {
760             TextureGL *sourceTexture = GetImplAs<TextureGL>(readBuffer->getTexture());
761             if (sourceTexture && sourceTexture->mTextureID == mTextureID)
762             {
763                 GLuint attachedTextureLevel = readBuffer->mipLevel();
764                 if (attachedTextureLevel != mState.getEffectiveBaseLevel())
765                 {
766                     ANGLE_TRY(setBaseLevel(context, attachedTextureLevel));
767                     ANGLE_TRY(setMaxLevel(context, attachedTextureLevel));
768                 }
769             }
770         }
771 
772         LevelInfoGL levelInfo =
773             GetLevelInfo(features, originalInternalFormatInfo, copyTexImageFormat.internalFormat);
774         gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
775 
776         if (levelInfo.lumaWorkaround.enabled)
777         {
778             BlitGL *blitter = GetBlitGL(context);
779 
780             if (requiresInitialization)
781             {
782                 ANGLE_TRY(blitter->copySubImageToLUMAWorkaroundTexture(
783                     context, mTextureID, getType(), target, levelInfo.sourceFormat, level,
784                     destOffset, clippedArea, source));
785             }
786             else
787             {
788                 ANGLE_TRY(blitter->copyImageToLUMAWorkaroundTexture(
789                     context, mTextureID, getType(), target, levelInfo.sourceFormat, level,
790                     clippedArea, copyTexImageFormat.internalFormat, source));
791             }
792         }
793         else
794         {
795             ASSERT(nativegl::UseTexImage2D(getType()));
796             stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER,
797                                           sourceFramebufferGL->getFramebufferID());
798             if (features.emulateCopyTexImage2DFromRenderbuffers.enabled && readBuffer &&
799                 readBuffer->type() == GL_RENDERBUFFER)
800             {
801                 BlitGL *blitter = GetBlitGL(context);
802                 ANGLE_TRY(blitter->blitColorBufferWithShader(
803                     context, source, mTextureID, target, level, clippedArea,
804                     gl::Rectangle(destOffset.x, destOffset.y, clippedArea.width,
805                                   clippedArea.height),
806                     GL_NEAREST, true));
807             }
808             else if (requiresInitialization)
809             {
810                 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
811                                           ToGLenum(target), static_cast<GLint>(level), destOffset.x,
812                                           destOffset.y, clippedArea.x, clippedArea.y,
813                                           clippedArea.width, clippedArea.height));
814             }
815             else
816             {
817                 if (features.emulateCopyTexImage2D.enabled)
818                 {
819                     if (type == GL_HALF_FLOAT_OES && functions->standard == STANDARD_GL_DESKTOP)
820                     {
821                         type = GL_HALF_FLOAT;
822                     }
823 
824                     ANGLE_GL_TRY_ALWAYS_CHECK(
825                         context,
826                         functions->texImage2D(
827                             ToGLenum(target), static_cast<GLint>(level),
828                             copyTexImageFormat.internalFormat, sourceArea.width, sourceArea.height,
829                             0, gl::GetUnsizedFormat(copyTexImageFormat.internalFormat), type,
830                             nullptr));
831                     ANGLE_GL_TRY_ALWAYS_CHECK(
832                         context,
833                         functions->copyTexSubImage2D(ToGLenum(target), static_cast<GLint>(level), 0,
834                                                      0, sourceArea.x, sourceArea.y,
835                                                      sourceArea.width, sourceArea.height));
836                 }
837                 else
838                 {
839                     ANGLE_GL_TRY_ALWAYS_CHECK(
840                         context, functions->copyTexImage2D(
841                                      ToGLenum(target), static_cast<GLint>(level),
842                                      copyTexImageFormat.internalFormat, sourceArea.x, sourceArea.y,
843                                      sourceArea.width, sourceArea.height, 0));
844                 }
845             }
846         }
847         setLevelInfo(context, target, level, 1, levelInfo);
848     }
849 
850     if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
851     {
852         contextGL->setNeedsFlushBeforeDeleteTextures();
853     }
854 
855     contextGL->markWorkSubmitted();
856     return angle::Result::Continue;
857 }
858 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)859 angle::Result TextureGL::copySubImage(const gl::Context *context,
860                                       const gl::ImageIndex &index,
861                                       const gl::Offset &destOffset,
862                                       const gl::Rectangle &sourceArea,
863                                       gl::Framebuffer *source)
864 {
865     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
866     const FunctionsGL *functions      = GetFunctionsGL(context);
867     StateManagerGL *stateManager      = GetStateManagerGL(context);
868     const angle::FeaturesGL &features = GetFeaturesGL(context);
869 
870     gl::TextureTarget target                 = index.getTarget();
871     size_t level                             = static_cast<size_t>(index.getLevelIndex());
872     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
873 
874     // Clip source area to framebuffer.
875     const gl::Extents fbSize = sourceFramebufferGL->getState().getReadAttachment()->getSize();
876     gl::Rectangle clippedArea;
877     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
878     {
879         // nothing to do
880         return angle::Result::Continue;
881     }
882     gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
883                              destOffset.y + clippedArea.y - sourceArea.y, destOffset.z);
884 
885     stateManager->bindTexture(getType(), mTextureID);
886     GLenum framebufferTarget =
887         stateManager->getHasSeparateFramebufferBindings() ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER;
888     stateManager->bindFramebuffer(framebufferTarget, sourceFramebufferGL->getFramebufferID());
889 
890     const LevelInfoGL &levelInfo = getLevelInfo(target, level);
891     if (levelInfo.lumaWorkaround.enabled)
892     {
893         BlitGL *blitter = GetBlitGL(context);
894         ANGLE_TRY(blitter->copySubImageToLUMAWorkaroundTexture(
895             context, mTextureID, getType(), target, levelInfo.sourceFormat, level, clippedOffset,
896             clippedArea, source));
897     }
898     else
899     {
900         if (nativegl::UseTexImage2D(getType()))
901         {
902             ASSERT(clippedOffset.z == 0);
903             if (features.emulateCopyTexImage2DFromRenderbuffers.enabled &&
904                 source->getReadColorAttachment() &&
905                 source->getReadColorAttachment()->type() == GL_RENDERBUFFER)
906             {
907                 BlitGL *blitter = GetBlitGL(context);
908                 ANGLE_TRY(blitter->blitColorBufferWithShader(
909                     context, source, mTextureID, target, level, clippedArea,
910                     gl::Rectangle(clippedOffset.x, clippedOffset.y, clippedArea.width,
911                                   clippedArea.height),
912                     GL_NEAREST, true));
913             }
914             else
915             {
916                 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
917                                           ToGLenum(target), static_cast<GLint>(level),
918                                           clippedOffset.x, clippedOffset.y, clippedArea.x,
919                                           clippedArea.y, clippedArea.width, clippedArea.height));
920             }
921         }
922         else
923         {
924             ASSERT(nativegl::UseTexImage3D(getType()));
925             ANGLE_GL_TRY(context, functions->copyTexSubImage3D(
926                                       ToGLenum(target), static_cast<GLint>(level), clippedOffset.x,
927                                       clippedOffset.y, clippedOffset.z, clippedArea.x,
928                                       clippedArea.y, clippedArea.width, clippedArea.height));
929         }
930     }
931 
932     if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
933     {
934         contextGL->setNeedsFlushBeforeDeleteTextures();
935     }
936 
937     contextGL->markWorkSubmitted();
938     return angle::Result::Continue;
939 }
940 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)941 angle::Result TextureGL::copyTexture(const gl::Context *context,
942                                      const gl::ImageIndex &index,
943                                      GLenum internalFormat,
944                                      GLenum type,
945                                      GLint sourceLevel,
946                                      bool unpackFlipY,
947                                      bool unpackPremultiplyAlpha,
948                                      bool unpackUnmultiplyAlpha,
949                                      const gl::Texture *source)
950 {
951     gl::TextureTarget target  = index.getTarget();
952     size_t level              = static_cast<size_t>(index.getLevelIndex());
953     const TextureGL *sourceGL = GetImplAs<TextureGL>(source);
954     const gl::ImageDesc &sourceImageDesc =
955         sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
956     gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
957 
958     ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat,
959                                         sourceImageDesc.size, gl::GetUnsizedFormat(internalFormat),
960                                         type));
961 
962     const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
963     return copySubTextureHelper(context, target, level, gl::Offset(0, 0, 0), sourceLevel,
964                                 sourceArea, destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
965                                 unpackUnmultiplyAlpha, source);
966 }
967 
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,GLint sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)968 angle::Result TextureGL::copySubTexture(const gl::Context *context,
969                                         const gl::ImageIndex &index,
970                                         const gl::Offset &destOffset,
971                                         GLint sourceLevel,
972                                         const gl::Box &sourceBox,
973                                         bool unpackFlipY,
974                                         bool unpackPremultiplyAlpha,
975                                         bool unpackUnmultiplyAlpha,
976                                         const gl::Texture *source)
977 {
978     gl::TextureTarget target                 = index.getTarget();
979     size_t level                             = static_cast<size_t>(index.getLevelIndex());
980     const gl::InternalFormat &destFormatInfo = *mState.getImageDesc(target, level).format.info;
981     return copySubTextureHelper(context, target, level, destOffset, sourceLevel, sourceBox.toRect(),
982                                 destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
983                                 unpackUnmultiplyAlpha, source);
984 }
985 
copySubTextureHelper(const gl::Context * context,gl::TextureTarget target,size_t level,const gl::Offset & destOffset,GLint sourceLevel,const gl::Rectangle & sourceArea,const gl::InternalFormat & destFormat,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)986 angle::Result TextureGL::copySubTextureHelper(const gl::Context *context,
987                                               gl::TextureTarget target,
988                                               size_t level,
989                                               const gl::Offset &destOffset,
990                                               GLint sourceLevel,
991                                               const gl::Rectangle &sourceArea,
992                                               const gl::InternalFormat &destFormat,
993                                               bool unpackFlipY,
994                                               bool unpackPremultiplyAlpha,
995                                               bool unpackUnmultiplyAlpha,
996                                               const gl::Texture *source)
997 {
998     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
999     const FunctionsGL *functions      = GetFunctionsGL(context);
1000     const angle::FeaturesGL &features = GetFeaturesGL(context);
1001     BlitGL *blitter                   = GetBlitGL(context);
1002 
1003     TextureGL *sourceGL = GetImplAs<TextureGL>(source);
1004     const gl::ImageDesc &sourceImageDesc =
1005         sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1006 
1007     if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
1008     {
1009         // Conservatively indicate that this workaround is necessary. Not clear
1010         // if it is on this code path, but added for symmetry.
1011         contextGL->setNeedsFlushBeforeDeleteTextures();
1012     }
1013 
1014     // Check is this is a simple copySubTexture that can be done with a copyTexSubImage
1015     ASSERT(sourceGL->getType() == gl::TextureType::_2D ||
1016            source->getType() == gl::TextureType::External ||
1017            source->getType() == gl::TextureType::Rectangle);
1018     const LevelInfoGL &sourceLevelInfo =
1019         sourceGL->getLevelInfo(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1020     bool needsLumaWorkaround = sourceLevelInfo.lumaWorkaround.enabled;
1021 
1022     const gl::InternalFormat &sourceFormatInfo = *sourceImageDesc.format.info;
1023     GLenum sourceFormat                        = sourceFormatInfo.format;
1024     bool sourceFormatContainSupersetOfDestFormat =
1025         (sourceFormat == destFormat.format && sourceFormat != GL_BGRA_EXT) ||
1026         (sourceFormat == GL_RGBA && destFormat.format == GL_RGB);
1027 
1028     GLenum sourceComponentType = sourceFormatInfo.componentType;
1029     GLenum destComponentType   = destFormat.componentType;
1030     bool destSRGB              = destFormat.colorEncoding == GL_SRGB;
1031     if (!unpackFlipY && unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !needsLumaWorkaround &&
1032         sourceFormatContainSupersetOfDestFormat && sourceComponentType == destComponentType &&
1033         !destSRGB && sourceGL->getType() == gl::TextureType::_2D)
1034     {
1035         bool copySucceeded = false;
1036         ANGLE_TRY(blitter->copyTexSubImage(context, sourceGL, sourceLevel, this, target, level,
1037                                            sourceArea, destOffset, &copySucceeded));
1038         if (copySucceeded)
1039         {
1040             contextGL->markWorkSubmitted();
1041             return angle::Result::Continue;
1042         }
1043     }
1044 
1045     // Check if the destination is renderable and copy on the GPU
1046     const LevelInfoGL &destLevelInfo = getLevelInfo(target, level);
1047     // todo(jonahr): http://crbug.com/773861
1048     // Behavior for now is to fallback to CPU readback implementation if the destination texture
1049     // is a luminance format. The correct solution is to handle both source and destination in the
1050     // luma workaround.
1051     if (!destSRGB && !destLevelInfo.lumaWorkaround.enabled &&
1052         nativegl::SupportsNativeRendering(functions, getType(), destLevelInfo.nativeInternalFormat))
1053     {
1054         bool copySucceeded = false;
1055         ANGLE_TRY(blitter->copySubTexture(
1056             context, sourceGL, sourceLevel, sourceComponentType, mTextureID, target, level,
1057             destComponentType, sourceImageDesc.size, sourceArea, destOffset, needsLumaWorkaround,
1058             sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
1059             unpackUnmultiplyAlpha, &copySucceeded));
1060         if (copySucceeded)
1061         {
1062             contextGL->markWorkSubmitted();
1063             return angle::Result::Continue;
1064         }
1065     }
1066 
1067     // Fall back to CPU-readback
1068     ANGLE_TRY(blitter->copySubTextureCPUReadback(
1069         context, sourceGL, sourceLevel, sourceFormatInfo.sizedInternalFormat, this, target, level,
1070         destFormat.format, destFormat.type, sourceImageDesc.size, sourceArea, destOffset,
1071         needsLumaWorkaround, sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
1072         unpackUnmultiplyAlpha));
1073     contextGL->markWorkSubmitted();
1074     return angle::Result::Continue;
1075 }
1076 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1077 angle::Result TextureGL::setStorage(const gl::Context *context,
1078                                     gl::TextureType type,
1079                                     size_t levels,
1080                                     GLenum internalFormat,
1081                                     const gl::Extents &size)
1082 {
1083     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1084     const FunctionsGL *functions      = GetFunctionsGL(context);
1085     StateManagerGL *stateManager      = GetStateManagerGL(context);
1086     const angle::FeaturesGL &features = GetFeaturesGL(context);
1087 
1088     const gl::InternalFormat &originalInternalFormatInfo =
1089         gl::GetSizedInternalFormatInfo(internalFormat);
1090     nativegl::TexStorageFormat texStorageFormat =
1091         nativegl::GetTexStorageFormat(functions, features, internalFormat);
1092 
1093     stateManager->bindTexture(getType(), mTextureID);
1094     if (nativegl::UseTexImage2D(getType()))
1095     {
1096         ASSERT(size.depth == 1);
1097         if (functions->texStorage2D)
1098         {
1099             ANGLE_GL_TRY_ALWAYS_CHECK(
1100                 context,
1101                 functions->texStorage2D(ToGLenum(type), static_cast<GLsizei>(levels),
1102                                         texStorageFormat.internalFormat, size.width, size.height));
1103         }
1104         else
1105         {
1106             // Make sure no pixel unpack buffer is bound
1107             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1108 
1109             const gl::InternalFormat &internalFormatInfo =
1110                 gl::GetSizedInternalFormatInfo(internalFormat);
1111 
1112             // Internal format must be sized
1113             ASSERT(internalFormatInfo.sized);
1114 
1115             for (size_t level = 0; level < levels; level++)
1116             {
1117                 gl::Extents levelSize(std::max(size.width >> level, 1),
1118                                       std::max(size.height >> level, 1), 1);
1119 
1120                 if (getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle)
1121                 {
1122                     if (internalFormatInfo.compressed)
1123                     {
1124                         nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1125                             nativegl::GetCompressedSubTexImageFormat(functions, features,
1126                                                                      internalFormat);
1127 
1128                         GLuint dataSize = 0;
1129                         ANGLE_CHECK_GL_MATH(
1130                             contextGL,
1131                             internalFormatInfo.computeCompressedImageSize(levelSize, &dataSize));
1132                         ANGLE_GL_TRY_ALWAYS_CHECK(
1133                             context,
1134                             functions->compressedTexImage2D(
1135                                 ToGLenum(type), static_cast<GLint>(level),
1136                                 compressedTexImageFormat.format, levelSize.width, levelSize.height,
1137                                 0, static_cast<GLsizei>(dataSize), nullptr));
1138                     }
1139                     else
1140                     {
1141                         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1142                             functions, features, internalFormat, internalFormatInfo.format,
1143                             internalFormatInfo.type);
1144 
1145                         ANGLE_GL_TRY_ALWAYS_CHECK(
1146                             context,
1147                             functions->texImage2D(ToGLenum(type), static_cast<GLint>(level),
1148                                                   texImageFormat.internalFormat, levelSize.width,
1149                                                   levelSize.height, 0, texImageFormat.format,
1150                                                   texImageFormat.type, nullptr));
1151                     }
1152                 }
1153                 else
1154                 {
1155                     ASSERT(getType() == gl::TextureType::CubeMap);
1156                     for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
1157                     {
1158                         if (internalFormatInfo.compressed)
1159                         {
1160                             nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1161                                 nativegl::GetCompressedSubTexImageFormat(functions, features,
1162                                                                          internalFormat);
1163 
1164                             GLuint dataSize = 0;
1165                             ANGLE_CHECK_GL_MATH(contextGL,
1166                                                 internalFormatInfo.computeCompressedImageSize(
1167                                                     levelSize, &dataSize));
1168                             ANGLE_GL_TRY_ALWAYS_CHECK(
1169                                 context,
1170                                 functions->compressedTexImage2D(
1171                                     ToGLenum(face), static_cast<GLint>(level),
1172                                     compressedTexImageFormat.format, levelSize.width,
1173                                     levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr));
1174                         }
1175                         else
1176                         {
1177                             nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1178                                 functions, features, internalFormat, internalFormatInfo.format,
1179                                 internalFormatInfo.type);
1180 
1181                             ANGLE_GL_TRY_ALWAYS_CHECK(
1182                                 context, functions->texImage2D(
1183                                              ToGLenum(face), static_cast<GLint>(level),
1184                                              texImageFormat.internalFormat, levelSize.width,
1185                                              levelSize.height, 0, texImageFormat.format,
1186                                              texImageFormat.type, nullptr));
1187                         }
1188                     }
1189                 }
1190             }
1191         }
1192     }
1193     else
1194     {
1195         ASSERT(nativegl::UseTexImage3D(getType()));
1196         const gl::InternalFormat &internalFormatInfo =
1197             gl::GetSizedInternalFormatInfo(internalFormat);
1198         const bool bypassTexStorage3D = type == gl::TextureType::_3D &&
1199                                         internalFormatInfo.compressed &&
1200                                         features.emulateImmutableCompressedTexture3D.enabled;
1201         if (functions->texStorage3D && !bypassTexStorage3D)
1202         {
1203             ANGLE_GL_TRY_ALWAYS_CHECK(
1204                 context, functions->texStorage3D(ToGLenum(type), static_cast<GLsizei>(levels),
1205                                                  texStorageFormat.internalFormat, size.width,
1206                                                  size.height, size.depth));
1207         }
1208         else
1209         {
1210             // Make sure no pixel unpack buffer is bound
1211             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1212 
1213             // Internal format must be sized
1214             ASSERT(internalFormatInfo.sized);
1215 
1216             for (GLsizei i = 0; i < static_cast<GLsizei>(levels); i++)
1217             {
1218                 gl::Extents levelSize(
1219                     std::max(size.width >> i, 1), std::max(size.height >> i, 1),
1220                     getType() == gl::TextureType::_3D ? std::max(size.depth >> i, 1) : size.depth);
1221 
1222                 if (internalFormatInfo.compressed)
1223                 {
1224                     nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1225                         nativegl::GetCompressedSubTexImageFormat(functions, features,
1226                                                                  internalFormat);
1227 
1228                     GLuint dataSize = 0;
1229                     ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computeCompressedImageSize(
1230                                                        levelSize, &dataSize));
1231                     ANGLE_GL_TRY_ALWAYS_CHECK(
1232                         context, functions->compressedTexImage3D(
1233                                      ToGLenum(type), i, compressedTexImageFormat.format,
1234                                      levelSize.width, levelSize.height, levelSize.depth, 0,
1235                                      static_cast<GLsizei>(dataSize), nullptr));
1236                 }
1237                 else
1238                 {
1239                     nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1240                         functions, features, internalFormat, internalFormatInfo.format,
1241                         internalFormatInfo.type);
1242 
1243                     ANGLE_GL_TRY_ALWAYS_CHECK(
1244                         context,
1245                         functions->texImage3D(ToGLenum(type), i, texImageFormat.internalFormat,
1246                                               levelSize.width, levelSize.height, levelSize.depth, 0,
1247                                               texImageFormat.format, texImageFormat.type, nullptr));
1248                 }
1249             }
1250         }
1251     }
1252 
1253     setLevelInfo(
1254         context, type, 0, levels,
1255         GetLevelInfo(features, originalInternalFormatInfo, texStorageFormat.internalFormat));
1256 
1257     return angle::Result::Continue;
1258 }
1259 
setImageExternal(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)1260 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1261                                           const gl::ImageIndex &index,
1262                                           GLenum internalFormat,
1263                                           const gl::Extents &size,
1264                                           GLenum format,
1265                                           GLenum type)
1266 {
1267     const FunctionsGL *functions      = GetFunctionsGL(context);
1268     const angle::FeaturesGL &features = GetFeaturesGL(context);
1269 
1270     gl::TextureTarget target = index.getTarget();
1271     size_t level             = static_cast<size_t>(index.getLevelIndex());
1272     const gl::InternalFormat &originalInternalFormatInfo =
1273         gl::GetInternalFormatInfo(internalFormat, type);
1274     nativegl::TexImageFormat texImageFormat =
1275         nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
1276 
1277     setLevelInfo(context, target, level, 1,
1278                  GetLevelInfo(features, originalInternalFormatInfo, texImageFormat.internalFormat));
1279     return angle::Result::Continue;
1280 }
1281 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1282 angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
1283                                                gl::TextureType type,
1284                                                GLsizei samples,
1285                                                GLint internalformat,
1286                                                const gl::Extents &size,
1287                                                bool fixedSampleLocations)
1288 {
1289     const FunctionsGL *functions      = GetFunctionsGL(context);
1290     StateManagerGL *stateManager      = GetStateManagerGL(context);
1291     const angle::FeaturesGL &features = GetFeaturesGL(context);
1292 
1293     const gl::InternalFormat &originalInternalFormatInfo =
1294         gl::GetSizedInternalFormatInfo(internalformat);
1295     nativegl::TexStorageFormat texStorageFormat =
1296         nativegl::GetTexStorageFormat(functions, features, internalformat);
1297 
1298     stateManager->bindTexture(getType(), mTextureID);
1299 
1300     if (nativegl::UseTexImage2D(getType()))
1301     {
1302         ASSERT(size.depth == 1);
1303         if (functions->texStorage2DMultisample)
1304         {
1305             ANGLE_GL_TRY_ALWAYS_CHECK(
1306                 context, functions->texStorage2DMultisample(
1307                              ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1308                              size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1309         }
1310         else
1311         {
1312             // texImage2DMultisample is similar to texStorage2DMultisample of es 3.1 core feature,
1313             // On macos and some old drivers which doesn't support OpenGL ES 3.1, the function can
1314             // be supported by ARB_texture_multisample or OpenGL 3.2 core feature.
1315             ANGLE_GL_TRY_ALWAYS_CHECK(
1316                 context, functions->texImage2DMultisample(
1317                              ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1318                              size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1319         }
1320     }
1321     else
1322     {
1323         ASSERT(nativegl::UseTexImage3D(getType()));
1324         ANGLE_GL_TRY_ALWAYS_CHECK(
1325             context, functions->texStorage3DMultisample(
1326                          ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1327                          size.height, size.depth, gl::ConvertToGLBoolean(fixedSampleLocations)));
1328     }
1329 
1330     setLevelInfo(
1331         context, type, 0, 1,
1332         GetLevelInfo(features, originalInternalFormatInfo, texStorageFormat.internalFormat));
1333 
1334     return angle::Result::Continue;
1335 }
1336 
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)1337 angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
1338                                                   gl::TextureType type,
1339                                                   size_t levels,
1340                                                   GLenum internalFormat,
1341                                                   const gl::Extents &size,
1342                                                   gl::MemoryObject *memoryObject,
1343                                                   GLuint64 offset,
1344                                                   GLbitfield createFlags,
1345                                                   GLbitfield usageFlags,
1346                                                   const void *imageCreateInfoPNext)
1347 {
1348     // GL_ANGLE_external_objects_flags not supported.
1349     ASSERT(createFlags == 0);
1350     ASSERT(usageFlags == std::numeric_limits<uint32_t>::max());
1351     ASSERT(imageCreateInfoPNext == nullptr);
1352 
1353     const FunctionsGL *functions      = GetFunctionsGL(context);
1354     StateManagerGL *stateManager      = GetStateManagerGL(context);
1355     const angle::FeaturesGL &features = GetFeaturesGL(context);
1356 
1357     MemoryObjectGL *memoryObjectGL = GetImplAs<MemoryObjectGL>(memoryObject);
1358 
1359     const gl::InternalFormat &originalInternalFormatInfo =
1360         gl::GetSizedInternalFormatInfo(internalFormat);
1361     nativegl::TexStorageFormat texStorageFormat =
1362         nativegl::GetTexStorageFormat(functions, features, internalFormat);
1363 
1364     stateManager->bindTexture(getType(), mTextureID);
1365     if (nativegl::UseTexImage2D(getType()))
1366     {
1367         ANGLE_GL_TRY_ALWAYS_CHECK(
1368             context,
1369             functions->texStorageMem2DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1370                                           texStorageFormat.internalFormat, size.width, size.height,
1371                                           memoryObjectGL->getMemoryObjectID(), offset));
1372     }
1373     else
1374     {
1375         ASSERT(nativegl::UseTexImage3D(getType()));
1376         ANGLE_GL_TRY_ALWAYS_CHECK(
1377             context,
1378             functions->texStorageMem3DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1379                                           texStorageFormat.internalFormat, size.width, size.height,
1380                                           size.depth, memoryObjectGL->getMemoryObjectID(), offset));
1381     }
1382 
1383     setLevelInfo(
1384         context, type, 0, levels,
1385         GetLevelInfo(features, originalInternalFormatInfo, texStorageFormat.internalFormat));
1386 
1387     return angle::Result::Continue;
1388 }
1389 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)1390 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1391                                           gl::TextureType type,
1392                                           egl::Stream *stream,
1393                                           const egl::Stream::GLTextureDescription &desc)
1394 {
1395     ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
1396     return angle::Result::Stop;
1397 }
1398 
generateMipmap(const gl::Context * context)1399 angle::Result TextureGL::generateMipmap(const gl::Context *context)
1400 {
1401     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1402     const FunctionsGL *functions      = GetFunctionsGL(context);
1403     StateManagerGL *stateManager      = GetStateManagerGL(context);
1404     const angle::FeaturesGL &features = GetFeaturesGL(context);
1405 
1406     const GLuint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1407     const GLuint maxLevel           = mState.getMipmapMaxLevel();
1408 
1409     const gl::ImageDesc &baseLevelDesc                = mState.getBaseLevelDesc();
1410     const gl::InternalFormat &baseLevelInternalFormat = *baseLevelDesc.format.info;
1411 
1412     stateManager->bindTexture(getType(), mTextureID);
1413     if (baseLevelInternalFormat.colorEncoding == GL_SRGB &&
1414         features.decodeEncodeSRGBForGenerateMipmap.enabled && getType() == gl::TextureType::_2D)
1415     {
1416         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1417             functions, features, baseLevelInternalFormat.internalFormat,
1418             baseLevelInternalFormat.format, baseLevelInternalFormat.type);
1419 
1420         // Manually allocate the mip levels of this texture if they don't exist
1421         GLuint levelCount = maxLevel - effectiveBaseLevel + 1;
1422         for (GLuint levelIdx = 1; levelIdx < levelCount; levelIdx++)
1423         {
1424             gl::Extents levelSize(std::max(baseLevelDesc.size.width >> levelIdx, 1),
1425                                   std::max(baseLevelDesc.size.height >> levelIdx, 1), 1);
1426 
1427             const gl::ImageDesc &levelDesc =
1428                 mState.getImageDesc(gl::TextureTarget::_2D, effectiveBaseLevel + levelIdx);
1429 
1430             // Make sure no pixel unpack buffer is bound
1431             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1432 
1433             if (levelDesc.size != levelSize || *levelDesc.format.info != baseLevelInternalFormat)
1434             {
1435                 ANGLE_GL_TRY_ALWAYS_CHECK(
1436                     context, functions->texImage2D(
1437                                  ToGLenum(getType()), effectiveBaseLevel + levelIdx,
1438                                  texImageFormat.internalFormat, levelSize.width, levelSize.height,
1439                                  0, texImageFormat.format, texImageFormat.type, nullptr));
1440             }
1441         }
1442 
1443         // Use the blitter to generate the mips
1444         BlitGL *blitter = GetBlitGL(context);
1445         ANGLE_TRY(blitter->generateSRGBMipmap(context, this, effectiveBaseLevel, levelCount,
1446                                               baseLevelDesc.size));
1447     }
1448     else
1449     {
1450         ANGLE_GL_TRY_ALWAYS_CHECK(context, functions->generateMipmap(ToGLenum(getType())));
1451     }
1452 
1453     setLevelInfo(context, getType(), effectiveBaseLevel, maxLevel - effectiveBaseLevel,
1454                  getBaseLevelInfo());
1455 
1456     contextGL->markWorkSubmitted();
1457     return angle::Result::Continue;
1458 }
1459 
bindTexImage(const gl::Context * context,egl::Surface * surface)1460 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1461 {
1462     ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1463 
1464     StateManagerGL *stateManager = GetStateManagerGL(context);
1465 
1466     // Make sure this texture is bound
1467     stateManager->bindTexture(getType(), mTextureID);
1468 
1469     SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1470 
1471     const gl::Format &surfaceFormat = surface->getBindTexImageFormat();
1472     setLevelInfo(context, getType(), 0, 1,
1473                  LevelInfoGL(surfaceFormat.info->format, surfaceFormat.info->internalFormat, false,
1474                              LUMAWorkaroundGL(), surfaceGL->hasEmulatedAlphaChannel()));
1475     return angle::Result::Continue;
1476 }
1477 
releaseTexImage(const gl::Context * context)1478 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1479 {
1480     ANGLE_TRY(recreateTexture(context));
1481     return angle::Result::Continue;
1482 }
1483 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1484 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1485                                            gl::TextureType type,
1486                                            egl::Image *image)
1487 {
1488     const angle::FeaturesGL &features = GetFeaturesGL(context);
1489 
1490     ImageGL *imageGL = GetImplAs<ImageGL>(image);
1491 
1492     GLenum imageNativeInternalFormat = GL_NONE;
1493     ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1494 
1495     const gl::InternalFormat &originalInternalFormatInfo = *image->getFormat().info;
1496 
1497     setLevelInfo(context, type, 0, 1,
1498                  GetLevelInfo(features, originalInternalFormatInfo, imageNativeInternalFormat));
1499 
1500     return angle::Result::Continue;
1501 }
1502 
getNativeID() const1503 GLint TextureGL::getNativeID() const
1504 {
1505     return mTextureID;
1506 }
1507 
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)1508 angle::Result TextureGL::syncState(const gl::Context *context,
1509                                    const gl::Texture::DirtyBits &dirtyBits,
1510                                    gl::Command source)
1511 {
1512     if (dirtyBits.none() && mLocalDirtyBits.none())
1513     {
1514         return angle::Result::Continue;
1515     }
1516 
1517     const FunctionsGL *functions = GetFunctionsGL(context);
1518     StateManagerGL *stateManager = GetStateManagerGL(context);
1519 
1520     stateManager->bindTexture(getType(), mTextureID);
1521 
1522     gl::Texture::DirtyBits syncDirtyBits = dirtyBits | mLocalDirtyBits;
1523     if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1524     {
1525         // Don't know if the previous base level was using any workarounds, always re-sync the
1526         // workaround dirty bits
1527         syncDirtyBits |= GetLevelWorkaroundDirtyBits();
1528     }
1529     for (auto dirtyBit : syncDirtyBits)
1530     {
1531 
1532         switch (dirtyBit)
1533         {
1534             case gl::Texture::DIRTY_BIT_MIN_FILTER:
1535                 mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter());
1536                 ANGLE_GL_TRY(context, functions->texParameteri(
1537                                           nativegl::GetTextureBindingTarget(getType()),
1538                                           GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1539                 break;
1540             case gl::Texture::DIRTY_BIT_MAG_FILTER:
1541                 mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter());
1542                 ANGLE_GL_TRY(context, functions->texParameteri(
1543                                           nativegl::GetTextureBindingTarget(getType()),
1544                                           GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1545                 break;
1546             case gl::Texture::DIRTY_BIT_WRAP_S:
1547                 mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS());
1548                 ANGLE_GL_TRY(context, functions->texParameteri(
1549                                           nativegl::GetTextureBindingTarget(getType()),
1550                                           GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1551                 break;
1552             case gl::Texture::DIRTY_BIT_WRAP_T:
1553                 mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT());
1554                 ANGLE_GL_TRY(context, functions->texParameteri(
1555                                           nativegl::GetTextureBindingTarget(getType()),
1556                                           GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1557                 break;
1558             case gl::Texture::DIRTY_BIT_WRAP_R:
1559                 mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR());
1560                 ANGLE_GL_TRY(context, functions->texParameteri(
1561                                           nativegl::GetTextureBindingTarget(getType()),
1562                                           GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1563                 break;
1564             case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1565                 mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy());
1566                 ANGLE_GL_TRY(context,
1567                              functions->texParameterf(nativegl::GetTextureBindingTarget(getType()),
1568                                                       GL_TEXTURE_MAX_ANISOTROPY_EXT,
1569                                                       mAppliedSampler.getMaxAnisotropy()));
1570                 break;
1571             case gl::Texture::DIRTY_BIT_MIN_LOD:
1572                 mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod());
1573                 ANGLE_GL_TRY(context, functions->texParameterf(
1574                                           nativegl::GetTextureBindingTarget(getType()),
1575                                           GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1576                 break;
1577             case gl::Texture::DIRTY_BIT_MAX_LOD:
1578                 mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod());
1579                 ANGLE_GL_TRY(context, functions->texParameterf(
1580                                           nativegl::GetTextureBindingTarget(getType()),
1581                                           GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1582                 break;
1583             case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1584                 mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode());
1585                 ANGLE_GL_TRY(context,
1586                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1587                                                       GL_TEXTURE_COMPARE_MODE,
1588                                                       mAppliedSampler.getCompareMode()));
1589                 break;
1590             case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1591                 mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc());
1592                 ANGLE_GL_TRY(context,
1593                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1594                                                       GL_TEXTURE_COMPARE_FUNC,
1595                                                       mAppliedSampler.getCompareFunc()));
1596                 break;
1597             case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1598                 mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode());
1599                 ANGLE_GL_TRY(context,
1600                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1601                                                       GL_TEXTURE_SRGB_DECODE_EXT,
1602                                                       mAppliedSampler.getSRGBDecode()));
1603                 break;
1604             case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1605             {
1606                 const LevelInfoGL &levelInfo    = getBaseLevelInfo();
1607                 angle::ColorGeneric borderColor = mState.getSamplerState().getBorderColor();
1608                 if (levelInfo.sourceFormat == GL_ALPHA)
1609                 {
1610                     if (levelInfo.lumaWorkaround.enabled)
1611                     {
1612                         ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1613                         borderColor.colorF.red = borderColor.colorF.alpha;
1614                     }
1615                     else
1616                     {
1617                         // Some ES drivers treat ALPHA as swizzled RG, triplicating
1618                         // border's red to RGB and sampling border's green as alpha.
1619                         borderColor.colorF.red   = 0.0f;
1620                         borderColor.colorF.green = borderColor.colorF.alpha;
1621                     }
1622                 }
1623                 else if (levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1624                 {
1625                     if (levelInfo.lumaWorkaround.enabled)
1626                     {
1627                         ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1628                     }
1629                     // When using desktop GL, this format is emulated as swizzled RG.
1630                     // Some ES drivers do the same without adjusting the border color.
1631                     borderColor.colorF.green = borderColor.colorF.alpha;
1632                 }
1633 
1634                 mAppliedSampler.setBorderColor(borderColor);
1635                 switch (borderColor.type)
1636                 {
1637                     case angle::ColorGeneric::Type::Float:
1638                         ANGLE_GL_TRY(context,
1639                                      functions->texParameterfv(
1640                                          nativegl::GetTextureBindingTarget(getType()),
1641                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1642                         break;
1643                     case angle::ColorGeneric::Type::Int:
1644                         ANGLE_GL_TRY(context,
1645                                      functions->texParameterIiv(
1646                                          nativegl::GetTextureBindingTarget(getType()),
1647                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1648                         break;
1649                     case angle::ColorGeneric::Type::UInt:
1650                         ANGLE_GL_TRY(context,
1651                                      functions->texParameterIuiv(
1652                                          nativegl::GetTextureBindingTarget(getType()),
1653                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1654                         break;
1655                     default:
1656                         UNREACHABLE();
1657                         break;
1658                 }
1659                 break;
1660             }
1661 
1662             // Texture state
1663             case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1664                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1665                                                   mState.getSwizzleState().swizzleRed,
1666                                                   &mAppliedSwizzle.swizzleRed));
1667                 break;
1668             case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1669                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1670                                                   mState.getSwizzleState().swizzleGreen,
1671                                                   &mAppliedSwizzle.swizzleGreen));
1672                 break;
1673             case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1674                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1675                                                   mState.getSwizzleState().swizzleBlue,
1676                                                   &mAppliedSwizzle.swizzleBlue));
1677                 break;
1678             case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1679                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1680                                                   mState.getSwizzleState().swizzleAlpha,
1681                                                   &mAppliedSwizzle.swizzleAlpha));
1682                 break;
1683             case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1684                 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1685                 ANGLE_GL_TRY(context,
1686                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1687                                                       GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1688                 break;
1689             case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1690                 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1691                 ANGLE_GL_TRY(context,
1692                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1693                                                       GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1694                 break;
1695             case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1696             {
1697                 GLenum mDepthStencilTextureMode = mState.getDepthStencilTextureMode();
1698                 ANGLE_GL_TRY(context, functions->texParameteri(
1699                                           nativegl::GetTextureBindingTarget(getType()),
1700                                           GL_DEPTH_STENCIL_TEXTURE_MODE, mDepthStencilTextureMode));
1701                 break;
1702             }
1703             case gl::Texture::DIRTY_BIT_USAGE:
1704             case gl::Texture::DIRTY_BIT_RENDERABILITY_VALIDATION_ANGLE:
1705                 break;
1706 
1707             case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1708                 // This special dirty bit is used to signal the front-end that the implementation
1709                 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1710                 break;
1711             case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1712             case gl::Texture::DIRTY_BIT_BOUND_AS_ATTACHMENT:
1713                 // Only used for Vulkan.
1714                 break;
1715 
1716             default:
1717                 UNREACHABLE();
1718         }
1719     }
1720 
1721     mAllModifiedDirtyBits |= syncDirtyBits;
1722     mLocalDirtyBits.reset();
1723     return angle::Result::Continue;
1724 }
1725 
hasAnyDirtyBit() const1726 bool TextureGL::hasAnyDirtyBit() const
1727 {
1728     return mLocalDirtyBits.any();
1729 }
1730 
setBaseLevel(const gl::Context * context,GLuint baseLevel)1731 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1732 {
1733     if (baseLevel != mAppliedBaseLevel)
1734     {
1735         const FunctionsGL *functions = GetFunctionsGL(context);
1736         StateManagerGL *stateManager = GetStateManagerGL(context);
1737 
1738         mAppliedBaseLevel = baseLevel;
1739         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1740 
1741         // Signal to the GL layer that the Impl has dirty bits.
1742         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1743 
1744         stateManager->bindTexture(getType(), mTextureID);
1745         ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1746                                                        baseLevel));
1747     }
1748     return angle::Result::Continue;
1749 }
1750 
setMaxLevel(const gl::Context * context,GLuint maxLevel)1751 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1752 {
1753     if (maxLevel != mAppliedMaxLevel)
1754     {
1755         const FunctionsGL *functions = GetFunctionsGL(context);
1756         StateManagerGL *stateManager = GetStateManagerGL(context);
1757 
1758         mAppliedMaxLevel = maxLevel;
1759         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1760 
1761         // Signal to the GL layer that the Impl has dirty bits.
1762         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1763 
1764         stateManager->bindTexture(getType(), mTextureID);
1765         ANGLE_GL_TRY(context,
1766                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1767     }
1768     return angle::Result::Continue;
1769 }
1770 
setMinFilter(const gl::Context * context,GLenum filter)1771 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1772 {
1773     if (mAppliedSampler.setMinFilter(filter))
1774     {
1775         const FunctionsGL *functions = GetFunctionsGL(context);
1776         StateManagerGL *stateManager = GetStateManagerGL(context);
1777 
1778         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1779 
1780         // Signal to the GL layer that the Impl has dirty bits.
1781         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1782 
1783         stateManager->bindTexture(getType(), mTextureID);
1784         ANGLE_GL_TRY(context,
1785                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1786     }
1787     return angle::Result::Continue;
1788 }
setMagFilter(const gl::Context * context,GLenum filter)1789 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1790 {
1791     if (mAppliedSampler.setMagFilter(filter))
1792     {
1793         const FunctionsGL *functions = GetFunctionsGL(context);
1794         StateManagerGL *stateManager = GetStateManagerGL(context);
1795 
1796         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1797 
1798         // Signal to the GL layer that the Impl has dirty bits.
1799         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1800 
1801         stateManager->bindTexture(getType(), mTextureID);
1802         ANGLE_GL_TRY(context,
1803                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1804     }
1805     return angle::Result::Continue;
1806 }
1807 
setSwizzle(const gl::Context * context,GLint swizzle[4])1808 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1809 {
1810     gl::SwizzleState resultingSwizzle =
1811         gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1812 
1813     if (resultingSwizzle != mAppliedSwizzle)
1814     {
1815         const FunctionsGL *functions = GetFunctionsGL(context);
1816         StateManagerGL *stateManager = GetStateManagerGL(context);
1817 
1818         mAppliedSwizzle = resultingSwizzle;
1819         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1820         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1821         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1822         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1823 
1824         // Signal to the GL layer that the Impl has dirty bits.
1825         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1826 
1827         stateManager->bindTexture(getType(), mTextureID);
1828         if (functions->standard == STANDARD_GL_ES)
1829         {
1830             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1831                                                            GL_TEXTURE_SWIZZLE_R, swizzle[0]));
1832             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1833                                                            GL_TEXTURE_SWIZZLE_G, swizzle[1]));
1834             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1835                                                            GL_TEXTURE_SWIZZLE_B, swizzle[2]));
1836             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1837                                                            GL_TEXTURE_SWIZZLE_A, swizzle[3]));
1838         }
1839         else
1840         {
1841             ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1842                                                             GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1843         }
1844     }
1845     return angle::Result::Continue;
1846 }
1847 
setBuffer(const gl::Context * context,GLenum internalFormat)1848 angle::Result TextureGL::setBuffer(const gl::Context *context, GLenum internalFormat)
1849 {
1850     const FunctionsGL *functions                              = GetFunctionsGL(context);
1851     const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
1852     const gl::Buffer *buffer                                  = bufferBinding.get();
1853     const GLintptr offset                                     = bufferBinding.getOffset();
1854     const GLsizeiptr size                                     = bufferBinding.getSize();
1855     const GLuint bufferID = buffer ? GetImplAs<BufferGL>(buffer)->getBufferID() : 0;
1856 
1857     // If buffer is not bound, use texBuffer to unbind it.  If size is 0, texBuffer was used to
1858     // create this binding, so use the same function.  This will allow the implementation to take
1859     // the current size of the buffer on every draw/dispatch call even if the buffer size changes.
1860     if (buffer == nullptr || size == 0)
1861     {
1862         ANGLE_GL_TRY(context, functions->texBuffer(GL_TEXTURE_BUFFER, internalFormat, bufferID));
1863     }
1864     else
1865     {
1866         ANGLE_GL_TRY(context,
1867                      functions->texBufferRange(GL_TEXTURE_BUFFER, internalFormat, bufferID, offset,
1868                                                GetBoundBufferAvailableSize(bufferBinding)));
1869     }
1870 
1871     return angle::Result::Continue;
1872 }
1873 
getNativeInternalFormat(const gl::ImageIndex & index) const1874 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1875 {
1876     return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1877 }
1878 
hasEmulatedAlphaChannel(const gl::ImageIndex & index) const1879 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1880 {
1881     return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1882         .emulatedAlphaChannel;
1883 }
1884 
recreateTexture(const gl::Context * context)1885 angle::Result TextureGL::recreateTexture(const gl::Context *context)
1886 {
1887     const FunctionsGL *functions = GetFunctionsGL(context);
1888     StateManagerGL *stateManager = GetStateManagerGL(context);
1889 
1890     stateManager->bindTexture(getType(), mTextureID);
1891     stateManager->deleteTexture(mTextureID);
1892 
1893     functions->genTextures(1, &mTextureID);
1894     stateManager->bindTexture(getType(), mTextureID);
1895 
1896     mLevelInfo.clear();
1897     mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
1898 
1899     mAppliedSwizzle = gl::SwizzleState();
1900     mAppliedSampler = gl::SamplerState::CreateDefaultForTarget(getType());
1901 
1902     mAppliedBaseLevel = 0;
1903     mAppliedBaseLevel = gl::kInitialMaxLevel;
1904 
1905     mLocalDirtyBits = mAllModifiedDirtyBits;
1906 
1907     onStateChange(angle::SubjectMessage::SubjectChanged);
1908 
1909     return angle::Result::Continue;
1910 }
1911 
syncTextureStateSwizzle(const gl::Context * context,const FunctionsGL * functions,GLenum name,GLenum value,GLenum * outValue)1912 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
1913                                                  const FunctionsGL *functions,
1914                                                  GLenum name,
1915                                                  GLenum value,
1916                                                  GLenum *outValue)
1917 {
1918     const LevelInfoGL &levelInfo = getBaseLevelInfo();
1919     GLenum resultSwizzle         = value;
1920     if (levelInfo.lumaWorkaround.enabled)
1921     {
1922         switch (value)
1923         {
1924             case GL_RED:
1925             case GL_GREEN:
1926             case GL_BLUE:
1927                 if (levelInfo.sourceFormat == GL_LUMINANCE ||
1928                     levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1929                 {
1930                     // Texture is backed by a RED or RG texture, point all color channels at the
1931                     // red channel.
1932                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
1933                            levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1934                     resultSwizzle = GL_RED;
1935                 }
1936                 else
1937                 {
1938                     ASSERT(levelInfo.sourceFormat == GL_ALPHA);
1939                     // Color channels are not supposed to exist, make them always sample 0.
1940                     resultSwizzle = GL_ZERO;
1941                 }
1942                 break;
1943 
1944             case GL_ALPHA:
1945                 if (levelInfo.sourceFormat == GL_LUMINANCE)
1946                 {
1947                     // Alpha channel is not supposed to exist, make it always sample 1.
1948                     resultSwizzle = GL_ONE;
1949                 }
1950                 else if (levelInfo.sourceFormat == GL_ALPHA)
1951                 {
1952                     // Texture is backed by a RED texture, point the alpha channel at the red
1953                     // channel.
1954                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1955                     resultSwizzle = GL_RED;
1956                 }
1957                 else
1958                 {
1959                     ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
1960                     // Texture is backed by an RG texture, point the alpha channel at the green
1961                     // channel.
1962                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1963                     resultSwizzle = GL_GREEN;
1964                 }
1965                 break;
1966 
1967             case GL_ZERO:
1968             case GL_ONE:
1969                 // Don't modify the swizzle state when requesting ZERO or ONE.
1970                 resultSwizzle = value;
1971                 break;
1972 
1973             default:
1974                 UNREACHABLE();
1975                 break;
1976         }
1977     }
1978     else if (levelInfo.depthStencilWorkaround)
1979     {
1980         switch (value)
1981         {
1982             case GL_RED:
1983                 // Don't modify the swizzle state when requesting the red channel.
1984                 resultSwizzle = value;
1985                 break;
1986 
1987             case GL_GREEN:
1988             case GL_BLUE:
1989                 if (context->getClientMajorVersion() <= 2)
1990                 {
1991                     // In OES_depth_texture/ARB_depth_texture, depth
1992                     // textures are treated as luminance.
1993                     resultSwizzle = GL_RED;
1994                 }
1995                 else
1996                 {
1997                     // In GLES 3.0, depth textures are treated as RED
1998                     // textures, so green and blue should be 0.
1999                     resultSwizzle = GL_ZERO;
2000                 }
2001                 break;
2002 
2003             case GL_ALPHA:
2004                 // Depth textures should sample 1 from the alpha channel.
2005                 resultSwizzle = GL_ONE;
2006                 break;
2007 
2008             case GL_ZERO:
2009             case GL_ONE:
2010                 // Don't modify the swizzle state when requesting ZERO or ONE.
2011                 resultSwizzle = value;
2012                 break;
2013 
2014             default:
2015                 UNREACHABLE();
2016                 break;
2017         }
2018     }
2019     else if (levelInfo.emulatedAlphaChannel)
2020     {
2021         if (value == GL_ALPHA)
2022         {
2023             resultSwizzle = GL_ONE;
2024         }
2025     }
2026 
2027     *outValue = resultSwizzle;
2028     ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
2029 
2030     return angle::Result::Continue;
2031 }
2032 
setLevelInfo(const gl::Context * context,gl::TextureTarget target,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)2033 void TextureGL::setLevelInfo(const gl::Context *context,
2034                              gl::TextureTarget target,
2035                              size_t level,
2036                              size_t levelCount,
2037                              const LevelInfoGL &levelInfo)
2038 {
2039     ASSERT(levelCount > 0);
2040 
2041     bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
2042                              levelInfo.emulatedAlphaChannel;
2043 
2044     for (size_t i = level; i < level + levelCount; i++)
2045     {
2046         size_t index = GetLevelInfoIndex(target, i);
2047         ASSERT(index < mLevelInfo.size());
2048         auto &curLevelInfo = mLevelInfo[index];
2049 
2050         updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
2051         updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
2052         updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
2053 
2054         curLevelInfo = levelInfo;
2055     }
2056 
2057     if (updateWorkarounds)
2058     {
2059         mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
2060         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
2061     }
2062 }
2063 
setLevelInfo(const gl::Context * context,gl::TextureType type,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)2064 void TextureGL::setLevelInfo(const gl::Context *context,
2065                              gl::TextureType type,
2066                              size_t level,
2067                              size_t levelCount,
2068                              const LevelInfoGL &levelInfo)
2069 {
2070     if (type == gl::TextureType::CubeMap)
2071     {
2072         for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
2073         {
2074             setLevelInfo(context, target, level, levelCount, levelInfo);
2075         }
2076     }
2077     else
2078     {
2079         setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
2080     }
2081 }
2082 
getLevelInfo(gl::TextureTarget target,size_t level) const2083 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
2084 {
2085     return mLevelInfo[GetLevelInfoIndex(target, level)];
2086 }
2087 
getBaseLevelInfo() const2088 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
2089 {
2090     GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
2091     gl::TextureTarget target = getType() == gl::TextureType::CubeMap
2092                                    ? gl::kCubeMapTextureTargetMin
2093                                    : gl::NonCubeTextureTypeToTarget(getType());
2094     return getLevelInfo(target, effectiveBaseLevel);
2095 }
2096 
getType() const2097 gl::TextureType TextureGL::getType() const
2098 {
2099     return mState.getType();
2100 }
2101 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)2102 angle::Result TextureGL::initializeContents(const gl::Context *context,
2103                                             GLenum binding,
2104                                             const gl::ImageIndex &imageIndex)
2105 {
2106     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
2107     const FunctionsGL *functions      = GetFunctionsGL(context);
2108     StateManagerGL *stateManager      = GetStateManagerGL(context);
2109     const angle::FeaturesGL &features = GetFeaturesGL(context);
2110 
2111     bool shouldUseClear = !nativegl::SupportsTexImage(getType());
2112     GLenum nativeInternalFormat =
2113         getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
2114     if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
2115         nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
2116     {
2117         BlitGL *blitter = GetBlitGL(context);
2118 
2119         int levelDepth = mState.getImageDesc(imageIndex).size.depth;
2120 
2121         bool clearSucceeded = false;
2122         ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
2123                                                   imageIndex, &clearSucceeded));
2124         if (clearSucceeded)
2125         {
2126             contextGL->markWorkSubmitted();
2127             return angle::Result::Continue;
2128         }
2129     }
2130 
2131     // Either the texture is not renderable or was incomplete when clearing, fall back to a data
2132     // upload
2133     ASSERT(nativegl::SupportsTexImage(getType()));
2134     const gl::ImageDesc &desc                    = mState.getImageDesc(imageIndex);
2135     const gl::InternalFormat &internalFormatInfo = *desc.format.info;
2136 
2137     gl::PixelUnpackState unpackState;
2138     unpackState.alignment = 1;
2139     ANGLE_TRY(stateManager->setPixelUnpackState(context, unpackState));
2140 
2141     GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
2142     stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
2143 
2144     stateManager->bindTexture(getType(), mTextureID);
2145     if (internalFormatInfo.compressed)
2146     {
2147         nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
2148             nativegl::GetCompressedSubTexImageFormat(functions, features,
2149                                                      internalFormatInfo.internalFormat);
2150 
2151         GLuint imageSize = 0;
2152         ANGLE_CHECK_GL_MATH(contextGL,
2153                             internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
2154 
2155         angle::MemoryBuffer *zero;
2156         ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2157 
2158         // WebGL spec requires that zero data is uploaded to compressed textures even if it might
2159         // not result in zero color data.
2160         if (nativegl::UseTexImage2D(getType()))
2161         {
2162             ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
2163                                       ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2164                                       0, 0, desc.size.width, desc.size.height,
2165                                       nativeSubImageFormat.format, imageSize, zero->data()));
2166         }
2167         else
2168         {
2169             ASSERT(nativegl::UseTexImage3D(getType()));
2170             ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
2171                                       ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2172                                       0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
2173                                       nativeSubImageFormat.format, imageSize, zero->data()));
2174         }
2175     }
2176     else
2177     {
2178         nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
2179             functions, features, internalFormatInfo.format, internalFormatInfo.type);
2180 
2181         GLuint imageSize = 0;
2182         ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
2183                                            nativeSubImageFormat.type, desc.size, unpackState,
2184                                            nativegl::UseTexImage3D(getType()), &imageSize));
2185 
2186         angle::MemoryBuffer *zero;
2187         ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2188 
2189         if (nativegl::UseTexImage2D(getType()))
2190         {
2191             if (features.uploadTextureDataInChunks.enabled)
2192             {
2193                 gl::Box area(0, 0, 0, desc.size.width, desc.size.height, 1);
2194                 ANGLE_TRY(setSubImageRowByRowWorkaround(
2195                     context, imageIndex.getTarget(), imageIndex.getLevelIndex(), area,
2196                     nativeSubImageFormat.format, nativeSubImageFormat.type, unpackState, nullptr,
2197                     kUploadTextureDataInChunksUploadSize, zero->data()));
2198             }
2199             else
2200             {
2201                 ANGLE_GL_TRY(context,
2202                              functions->texSubImage2D(
2203                                  ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0,
2204                                  desc.size.width, desc.size.height, nativeSubImageFormat.format,
2205                                  nativeSubImageFormat.type, zero->data()));
2206             }
2207         }
2208         else
2209         {
2210             ASSERT(nativegl::UseTexImage3D(getType()));
2211             ANGLE_GL_TRY(context,
2212                          functions->texSubImage3D(
2213                              ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
2214                              desc.size.width, desc.size.height, desc.size.depth,
2215                              nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
2216         }
2217     }
2218 
2219     // Reset the pixel unpack state.  Because this call is made after synchronizing dirty bits in a
2220     // glTexImage call, we need to make sure that the texture data to be uploaded later has the
2221     // expected unpack state.
2222     ANGLE_TRY(stateManager->setPixelUnpackState(context, context->getState().getUnpackState()));
2223     stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
2224 
2225     contextGL->markWorkSubmitted();
2226     return angle::Result::Continue;
2227 }
2228 
getRequiredExternalTextureImageUnits(const gl::Context * context)2229 GLint TextureGL::getRequiredExternalTextureImageUnits(const gl::Context *context)
2230 {
2231     const FunctionsGL *functions = GetFunctionsGL(context);
2232     StateManagerGL *stateManager = GetStateManagerGL(context);
2233 
2234     ASSERT(getType() == gl::TextureType::External);
2235     stateManager->bindTexture(getType(), mTextureID);
2236 
2237     GLint result = 0;
2238     functions->getTexParameteriv(ToGLenum(gl::NonCubeTextureTypeToTarget(getType())),
2239                                  GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &result);
2240     return result;
2241 }
2242 
2243 }  // namespace rx
2244