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