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