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         if (functions->texStorage3D)
1131         {
1132             ANGLE_GL_TRY_ALWAYS_CHECK(
1133                 context, functions->texStorage3D(ToGLenum(type), static_cast<GLsizei>(levels),
1134                                                  texStorageFormat.internalFormat, size.width,
1135                                                  size.height, size.depth));
1136         }
1137         else
1138         {
1139             // Make sure no pixel unpack buffer is bound
1140             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1141 
1142             const gl::InternalFormat &internalFormatInfo =
1143                 gl::GetSizedInternalFormatInfo(internalFormat);
1144 
1145             // Internal format must be sized
1146             ASSERT(internalFormatInfo.sized);
1147 
1148             for (GLsizei i = 0; i < static_cast<GLsizei>(levels); i++)
1149             {
1150                 gl::Extents levelSize(
1151                     std::max(size.width >> i, 1), std::max(size.height >> i, 1),
1152                     getType() == gl::TextureType::_3D ? std::max(size.depth >> i, 1) : size.depth);
1153 
1154                 if (internalFormatInfo.compressed)
1155                 {
1156                     nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1157                         nativegl::GetCompressedSubTexImageFormat(functions, features,
1158                                                                  internalFormat);
1159 
1160                     GLuint dataSize = 0;
1161                     ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computeCompressedImageSize(
1162                                                        levelSize, &dataSize));
1163                     ANGLE_GL_TRY_ALWAYS_CHECK(
1164                         context, functions->compressedTexImage3D(
1165                                      ToGLenum(type), i, compressedTexImageFormat.format,
1166                                      levelSize.width, levelSize.height, levelSize.depth, 0,
1167                                      static_cast<GLsizei>(dataSize), nullptr));
1168                 }
1169                 else
1170                 {
1171                     nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1172                         functions, features, internalFormat, internalFormatInfo.format,
1173                         internalFormatInfo.type);
1174 
1175                     ANGLE_GL_TRY_ALWAYS_CHECK(
1176                         context,
1177                         functions->texImage3D(ToGLenum(type), i, texImageFormat.internalFormat,
1178                                               levelSize.width, levelSize.height, levelSize.depth, 0,
1179                                               texImageFormat.format, texImageFormat.type, nullptr));
1180                 }
1181             }
1182         }
1183     }
1184 
1185     setLevelInfo(context, type, 0, levels,
1186                  GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1187 
1188     return angle::Result::Continue;
1189 }
1190 
setImageExternal(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type)1191 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1192                                           const gl::ImageIndex &index,
1193                                           GLenum internalFormat,
1194                                           const gl::Extents &size,
1195                                           GLenum format,
1196                                           GLenum type)
1197 {
1198     const FunctionsGL *functions      = GetFunctionsGL(context);
1199     const angle::FeaturesGL &features = GetFeaturesGL(context);
1200 
1201     gl::TextureTarget target = index.getTarget();
1202     size_t level             = static_cast<size_t>(index.getLevelIndex());
1203     nativegl::TexImageFormat texImageFormat =
1204         nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
1205 
1206     setLevelInfo(context, target, level, 1,
1207                  GetLevelInfo(features, internalFormat, texImageFormat.internalFormat));
1208     return angle::Result::Continue;
1209 }
1210 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)1211 angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
1212                                                gl::TextureType type,
1213                                                GLsizei samples,
1214                                                GLint internalformat,
1215                                                const gl::Extents &size,
1216                                                bool fixedSampleLocations)
1217 {
1218     const FunctionsGL *functions      = GetFunctionsGL(context);
1219     StateManagerGL *stateManager      = GetStateManagerGL(context);
1220     const angle::FeaturesGL &features = GetFeaturesGL(context);
1221 
1222     nativegl::TexStorageFormat texStorageFormat =
1223         nativegl::GetTexStorageFormat(functions, features, internalformat);
1224 
1225     stateManager->bindTexture(getType(), mTextureID);
1226 
1227     if (nativegl::UseTexImage2D(getType()))
1228     {
1229         ASSERT(size.depth == 1);
1230         if (functions->texStorage2DMultisample)
1231         {
1232             ANGLE_GL_TRY_ALWAYS_CHECK(
1233                 context, functions->texStorage2DMultisample(
1234                              ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1235                              size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1236         }
1237         else
1238         {
1239             // texImage2DMultisample is similar to texStorage2DMultisample of es 3.1 core feature,
1240             // On macos and some old drivers which doesn't support OpenGL ES 3.1, the function can
1241             // be supported by ARB_texture_multisample or OpenGL 3.2 core feature.
1242             ANGLE_GL_TRY_ALWAYS_CHECK(
1243                 context, functions->texImage2DMultisample(
1244                              ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1245                              size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1246         }
1247     }
1248     else
1249     {
1250         ASSERT(nativegl::UseTexImage3D(getType()));
1251         ANGLE_GL_TRY_ALWAYS_CHECK(
1252             context, functions->texStorage3DMultisample(
1253                          ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1254                          size.height, size.depth, gl::ConvertToGLBoolean(fixedSampleLocations)));
1255     }
1256 
1257     setLevelInfo(context, type, 0, 1,
1258                  GetLevelInfo(features, internalformat, texStorageFormat.internalFormat));
1259 
1260     return angle::Result::Continue;
1261 }
1262 
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)1263 angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
1264                                                   gl::TextureType type,
1265                                                   size_t levels,
1266                                                   GLenum internalFormat,
1267                                                   const gl::Extents &size,
1268                                                   gl::MemoryObject *memoryObject,
1269                                                   GLuint64 offset,
1270                                                   GLbitfield createFlags,
1271                                                   GLbitfield usageFlags)
1272 {
1273     // GL_ANGLE_external_objects_flags not supported.
1274     ASSERT(createFlags == 0);
1275     ASSERT(usageFlags == std::numeric_limits<uint32_t>::max());
1276 
1277     const FunctionsGL *functions      = GetFunctionsGL(context);
1278     StateManagerGL *stateManager      = GetStateManagerGL(context);
1279     const angle::FeaturesGL &features = GetFeaturesGL(context);
1280 
1281     MemoryObjectGL *memoryObjectGL = GetImplAs<MemoryObjectGL>(memoryObject);
1282 
1283     nativegl::TexStorageFormat texStorageFormat =
1284         nativegl::GetTexStorageFormat(functions, features, internalFormat);
1285 
1286     stateManager->bindTexture(getType(), mTextureID);
1287     if (nativegl::UseTexImage2D(getType()))
1288     {
1289         ANGLE_GL_TRY_ALWAYS_CHECK(
1290             context,
1291             functions->texStorageMem2DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1292                                           texStorageFormat.internalFormat, size.width, size.height,
1293                                           memoryObjectGL->getMemoryObjectID(), offset));
1294     }
1295     else
1296     {
1297         ASSERT(nativegl::UseTexImage3D(getType()));
1298         ANGLE_GL_TRY_ALWAYS_CHECK(
1299             context,
1300             functions->texStorageMem3DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1301                                           texStorageFormat.internalFormat, size.width, size.height,
1302                                           size.depth, memoryObjectGL->getMemoryObjectID(), offset));
1303     }
1304 
1305     setLevelInfo(context, type, 0, levels,
1306                  GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1307 
1308     return angle::Result::Continue;
1309 }
1310 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)1311 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1312                                           gl::TextureType type,
1313                                           egl::Stream *stream,
1314                                           const egl::Stream::GLTextureDescription &desc)
1315 {
1316     ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
1317     return angle::Result::Stop;
1318 }
1319 
generateMipmap(const gl::Context * context)1320 angle::Result TextureGL::generateMipmap(const gl::Context *context)
1321 {
1322     const FunctionsGL *functions      = GetFunctionsGL(context);
1323     StateManagerGL *stateManager      = GetStateManagerGL(context);
1324     const angle::FeaturesGL &features = GetFeaturesGL(context);
1325 
1326     const GLuint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1327     const GLuint maxLevel           = mState.getMipmapMaxLevel();
1328 
1329     const gl::ImageDesc &baseLevelDesc                = mState.getBaseLevelDesc();
1330     const gl::InternalFormat &baseLevelInternalFormat = *baseLevelDesc.format.info;
1331 
1332     stateManager->bindTexture(getType(), mTextureID);
1333     if (baseLevelInternalFormat.colorEncoding == GL_SRGB &&
1334         features.encodeAndDecodeSRGBForGenerateMipmap.enabled && getType() == gl::TextureType::_2D)
1335     {
1336         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1337             functions, features, baseLevelInternalFormat.internalFormat,
1338             baseLevelInternalFormat.format, baseLevelInternalFormat.type);
1339 
1340         // Manually allocate the mip levels of this texture if they don't exist
1341         GLuint levelCount = maxLevel - effectiveBaseLevel + 1;
1342         for (GLuint levelIdx = 1; levelIdx < levelCount; levelIdx++)
1343         {
1344             gl::Extents levelSize(std::max(baseLevelDesc.size.width >> levelIdx, 1),
1345                                   std::max(baseLevelDesc.size.height >> levelIdx, 1), 1);
1346 
1347             const gl::ImageDesc &levelDesc =
1348                 mState.getImageDesc(gl::TextureTarget::_2D, effectiveBaseLevel + levelIdx);
1349 
1350             // Make sure no pixel unpack buffer is bound
1351             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1352 
1353             if (levelDesc.size != levelSize || *levelDesc.format.info != baseLevelInternalFormat)
1354             {
1355                 ANGLE_GL_TRY_ALWAYS_CHECK(
1356                     context, functions->texImage2D(
1357                                  ToGLenum(getType()), effectiveBaseLevel + levelIdx,
1358                                  texImageFormat.internalFormat, levelSize.width, levelSize.height,
1359                                  0, texImageFormat.format, texImageFormat.type, nullptr));
1360             }
1361         }
1362 
1363         // Use the blitter to generate the mips
1364         BlitGL *blitter = GetBlitGL(context);
1365         ANGLE_TRY(blitter->generateSRGBMipmap(context, this, effectiveBaseLevel, levelCount,
1366                                               baseLevelDesc.size));
1367     }
1368     else
1369     {
1370         ANGLE_GL_TRY_ALWAYS_CHECK(context, functions->generateMipmap(ToGLenum(getType())));
1371     }
1372 
1373     setLevelInfo(context, getType(), effectiveBaseLevel, maxLevel - effectiveBaseLevel,
1374                  getBaseLevelInfo());
1375 
1376     return angle::Result::Continue;
1377 }
1378 
bindTexImage(const gl::Context * context,egl::Surface * surface)1379 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1380 {
1381     ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1382 
1383     StateManagerGL *stateManager = GetStateManagerGL(context);
1384 
1385     // Make sure this texture is bound
1386     stateManager->bindTexture(getType(), mTextureID);
1387 
1388     SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1389 
1390     const gl::Format &surfaceFormat = surface->getBindTexImageFormat();
1391     setLevelInfo(context, getType(), 0, 1,
1392                  LevelInfoGL(surfaceFormat.info->format, surfaceFormat.info->internalFormat, false,
1393                              LUMAWorkaroundGL(), surfaceGL->hasEmulatedAlphaChannel()));
1394     return angle::Result::Continue;
1395 }
1396 
releaseTexImage(const gl::Context * context)1397 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1398 {
1399     ANGLE_TRY(recreateTexture(context));
1400     return angle::Result::Continue;
1401 }
1402 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1403 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1404                                            gl::TextureType type,
1405                                            egl::Image *image)
1406 {
1407     const angle::FeaturesGL &features = GetFeaturesGL(context);
1408 
1409     ImageGL *imageGL = GetImplAs<ImageGL>(image);
1410 
1411     GLenum imageNativeInternalFormat = GL_NONE;
1412     ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1413 
1414     setLevelInfo(
1415         context, type, 0, 1,
1416         GetLevelInfo(features, image->getFormat().info->internalFormat, imageNativeInternalFormat));
1417 
1418     return angle::Result::Continue;
1419 }
1420 
getNativeID() const1421 GLint TextureGL::getNativeID() const
1422 {
1423     return mTextureID;
1424 }
1425 
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits,gl::Command source)1426 angle::Result TextureGL::syncState(const gl::Context *context,
1427                                    const gl::Texture::DirtyBits &dirtyBits,
1428                                    gl::Command source)
1429 {
1430     if (dirtyBits.none() && mLocalDirtyBits.none())
1431     {
1432         return angle::Result::Continue;
1433     }
1434 
1435     const FunctionsGL *functions = GetFunctionsGL(context);
1436     StateManagerGL *stateManager = GetStateManagerGL(context);
1437 
1438     stateManager->bindTexture(getType(), mTextureID);
1439 
1440     gl::Texture::DirtyBits syncDirtyBits = dirtyBits | mLocalDirtyBits;
1441     if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1442     {
1443         // Don't know if the previous base level was using any workarounds, always re-sync the
1444         // workaround dirty bits
1445         syncDirtyBits |= GetLevelWorkaroundDirtyBits();
1446     }
1447     for (auto dirtyBit : syncDirtyBits)
1448     {
1449 
1450         switch (dirtyBit)
1451         {
1452             case gl::Texture::DIRTY_BIT_MIN_FILTER:
1453                 mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter());
1454                 ANGLE_GL_TRY(context, functions->texParameteri(
1455                                           nativegl::GetTextureBindingTarget(getType()),
1456                                           GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1457                 break;
1458             case gl::Texture::DIRTY_BIT_MAG_FILTER:
1459                 mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter());
1460                 ANGLE_GL_TRY(context, functions->texParameteri(
1461                                           nativegl::GetTextureBindingTarget(getType()),
1462                                           GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1463                 break;
1464             case gl::Texture::DIRTY_BIT_WRAP_S:
1465                 mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS());
1466                 ANGLE_GL_TRY(context, functions->texParameteri(
1467                                           nativegl::GetTextureBindingTarget(getType()),
1468                                           GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1469                 break;
1470             case gl::Texture::DIRTY_BIT_WRAP_T:
1471                 mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT());
1472                 ANGLE_GL_TRY(context, functions->texParameteri(
1473                                           nativegl::GetTextureBindingTarget(getType()),
1474                                           GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1475                 break;
1476             case gl::Texture::DIRTY_BIT_WRAP_R:
1477                 mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR());
1478                 ANGLE_GL_TRY(context, functions->texParameteri(
1479                                           nativegl::GetTextureBindingTarget(getType()),
1480                                           GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1481                 break;
1482             case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1483                 mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy());
1484                 ANGLE_GL_TRY(context,
1485                              functions->texParameterf(nativegl::GetTextureBindingTarget(getType()),
1486                                                       GL_TEXTURE_MAX_ANISOTROPY_EXT,
1487                                                       mAppliedSampler.getMaxAnisotropy()));
1488                 break;
1489             case gl::Texture::DIRTY_BIT_MIN_LOD:
1490                 mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod());
1491                 ANGLE_GL_TRY(context, functions->texParameterf(
1492                                           nativegl::GetTextureBindingTarget(getType()),
1493                                           GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1494                 break;
1495             case gl::Texture::DIRTY_BIT_MAX_LOD:
1496                 mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod());
1497                 ANGLE_GL_TRY(context, functions->texParameterf(
1498                                           nativegl::GetTextureBindingTarget(getType()),
1499                                           GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1500                 break;
1501             case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1502                 mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode());
1503                 ANGLE_GL_TRY(context,
1504                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1505                                                       GL_TEXTURE_COMPARE_MODE,
1506                                                       mAppliedSampler.getCompareMode()));
1507                 break;
1508             case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1509                 mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc());
1510                 ANGLE_GL_TRY(context,
1511                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1512                                                       GL_TEXTURE_COMPARE_FUNC,
1513                                                       mAppliedSampler.getCompareFunc()));
1514                 break;
1515             case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1516                 mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode());
1517                 ANGLE_GL_TRY(context,
1518                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1519                                                       GL_TEXTURE_SRGB_DECODE_EXT,
1520                                                       mAppliedSampler.getSRGBDecode()));
1521                 break;
1522             case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1523             {
1524                 const angle::ColorGeneric &borderColor(mState.getSamplerState().getBorderColor());
1525                 mAppliedSampler.setBorderColor(borderColor);
1526                 switch (borderColor.type)
1527                 {
1528                     case angle::ColorGeneric::Type::Float:
1529                         ANGLE_GL_TRY(context,
1530                                      functions->texParameterfv(
1531                                          nativegl::GetTextureBindingTarget(getType()),
1532                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1533                         break;
1534                     case angle::ColorGeneric::Type::Int:
1535                         ANGLE_GL_TRY(context,
1536                                      functions->texParameterIiv(
1537                                          nativegl::GetTextureBindingTarget(getType()),
1538                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1539                         break;
1540                     case angle::ColorGeneric::Type::UInt:
1541                         ANGLE_GL_TRY(context,
1542                                      functions->texParameterIuiv(
1543                                          nativegl::GetTextureBindingTarget(getType()),
1544                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1545                         break;
1546                     default:
1547                         UNREACHABLE();
1548                         break;
1549                 }
1550                 break;
1551             }
1552 
1553             // Texture state
1554             case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1555                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1556                                                   mState.getSwizzleState().swizzleRed,
1557                                                   &mAppliedSwizzle.swizzleRed));
1558                 break;
1559             case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1560                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1561                                                   mState.getSwizzleState().swizzleGreen,
1562                                                   &mAppliedSwizzle.swizzleGreen));
1563                 break;
1564             case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1565                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1566                                                   mState.getSwizzleState().swizzleBlue,
1567                                                   &mAppliedSwizzle.swizzleBlue));
1568                 break;
1569             case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1570                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1571                                                   mState.getSwizzleState().swizzleAlpha,
1572                                                   &mAppliedSwizzle.swizzleAlpha));
1573                 break;
1574             case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1575                 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1576                 ANGLE_GL_TRY(context,
1577                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1578                                                       GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1579                 break;
1580             case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1581                 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1582                 ANGLE_GL_TRY(context,
1583                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1584                                                       GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1585                 break;
1586             case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1587             {
1588                 GLenum mDepthStencilTextureMode = mState.getDepthStencilTextureMode();
1589                 ANGLE_GL_TRY(context, functions->texParameteri(
1590                                           nativegl::GetTextureBindingTarget(getType()),
1591                                           GL_DEPTH_STENCIL_TEXTURE_MODE, mDepthStencilTextureMode));
1592                 break;
1593             }
1594             case gl::Texture::DIRTY_BIT_USAGE:
1595                 break;
1596             case gl::Texture::DIRTY_BIT_LABEL:
1597                 break;
1598 
1599             case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1600                 // This special dirty bit is used to signal the front-end that the implementation
1601                 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1602                 break;
1603             case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1604                 // Only used for Vulkan.
1605                 break;
1606 
1607             default:
1608                 UNREACHABLE();
1609         }
1610     }
1611 
1612     mAllModifiedDirtyBits |= syncDirtyBits;
1613     mLocalDirtyBits.reset();
1614     return angle::Result::Continue;
1615 }
1616 
hasAnyDirtyBit() const1617 bool TextureGL::hasAnyDirtyBit() const
1618 {
1619     return mLocalDirtyBits.any();
1620 }
1621 
setBaseLevel(const gl::Context * context,GLuint baseLevel)1622 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1623 {
1624     if (baseLevel != mAppliedBaseLevel)
1625     {
1626         const FunctionsGL *functions = GetFunctionsGL(context);
1627         StateManagerGL *stateManager = GetStateManagerGL(context);
1628 
1629         mAppliedBaseLevel = baseLevel;
1630         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1631 
1632         // Signal to the GL layer that the Impl has dirty bits.
1633         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1634 
1635         stateManager->bindTexture(getType(), mTextureID);
1636         ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1637                                                        baseLevel));
1638     }
1639     return angle::Result::Continue;
1640 }
1641 
setMaxLevel(const gl::Context * context,GLuint maxLevel)1642 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1643 {
1644     if (maxLevel != mAppliedMaxLevel)
1645     {
1646         const FunctionsGL *functions = GetFunctionsGL(context);
1647         StateManagerGL *stateManager = GetStateManagerGL(context);
1648 
1649         mAppliedMaxLevel = maxLevel;
1650         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1651 
1652         // Signal to the GL layer that the Impl has dirty bits.
1653         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1654 
1655         stateManager->bindTexture(getType(), mTextureID);
1656         ANGLE_GL_TRY(context,
1657                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1658     }
1659     return angle::Result::Continue;
1660 }
1661 
setMinFilter(const gl::Context * context,GLenum filter)1662 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1663 {
1664     if (mAppliedSampler.setMinFilter(filter))
1665     {
1666         const FunctionsGL *functions = GetFunctionsGL(context);
1667         StateManagerGL *stateManager = GetStateManagerGL(context);
1668 
1669         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1670 
1671         // Signal to the GL layer that the Impl has dirty bits.
1672         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1673 
1674         stateManager->bindTexture(getType(), mTextureID);
1675         ANGLE_GL_TRY(context,
1676                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1677     }
1678     return angle::Result::Continue;
1679 }
setMagFilter(const gl::Context * context,GLenum filter)1680 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1681 {
1682     if (mAppliedSampler.setMagFilter(filter))
1683     {
1684         const FunctionsGL *functions = GetFunctionsGL(context);
1685         StateManagerGL *stateManager = GetStateManagerGL(context);
1686 
1687         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1688 
1689         // Signal to the GL layer that the Impl has dirty bits.
1690         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1691 
1692         stateManager->bindTexture(getType(), mTextureID);
1693         ANGLE_GL_TRY(context,
1694                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1695     }
1696     return angle::Result::Continue;
1697 }
1698 
setSwizzle(const gl::Context * context,GLint swizzle[4])1699 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1700 {
1701     gl::SwizzleState resultingSwizzle =
1702         gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1703 
1704     if (resultingSwizzle != mAppliedSwizzle)
1705     {
1706         const FunctionsGL *functions = GetFunctionsGL(context);
1707         StateManagerGL *stateManager = GetStateManagerGL(context);
1708 
1709         mAppliedSwizzle = resultingSwizzle;
1710         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1711         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1712         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1713         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1714 
1715         // Signal to the GL layer that the Impl has dirty bits.
1716         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1717 
1718         stateManager->bindTexture(getType(), mTextureID);
1719         if (functions->standard == STANDARD_GL_ES)
1720         {
1721             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1722                                                            GL_TEXTURE_SWIZZLE_R, swizzle[0]));
1723             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1724                                                            GL_TEXTURE_SWIZZLE_G, swizzle[1]));
1725             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1726                                                            GL_TEXTURE_SWIZZLE_B, swizzle[2]));
1727             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1728                                                            GL_TEXTURE_SWIZZLE_A, swizzle[3]));
1729         }
1730         else
1731         {
1732             ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1733                                                             GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1734         }
1735     }
1736     return angle::Result::Continue;
1737 }
1738 
setBuffer(const gl::Context * context,GLenum internalFormat)1739 angle::Result TextureGL::setBuffer(const gl::Context *context, GLenum internalFormat)
1740 {
1741     const FunctionsGL *functions                              = GetFunctionsGL(context);
1742     const gl::OffsetBindingPointer<gl::Buffer> &bufferBinding = mState.getBuffer();
1743     const gl::Buffer *buffer                                  = bufferBinding.get();
1744     const GLintptr offset                                     = bufferBinding.getOffset();
1745     const GLsizeiptr size                                     = bufferBinding.getSize();
1746     const GLuint bufferID = buffer ? GetImplAs<BufferGL>(buffer)->getBufferID() : 0;
1747 
1748     // If buffer is not bound, use texBuffer to unbind it.  If size is 0, texBuffer was used to
1749     // create this binding, so use the same function.  This will allow the implementation to take
1750     // the current size of the buffer on every draw/dispatch call even if the buffer size changes.
1751     if (buffer == nullptr || size == 0)
1752     {
1753         ANGLE_GL_TRY(context, functions->texBuffer(GL_TEXTURE_BUFFER, internalFormat, bufferID));
1754     }
1755     else
1756     {
1757         ANGLE_GL_TRY(context,
1758                      functions->texBufferRange(GL_TEXTURE_BUFFER, internalFormat, bufferID, offset,
1759                                                GetBoundBufferAvailableSize(bufferBinding)));
1760     }
1761 
1762     return angle::Result::Continue;
1763 }
1764 
getNativeInternalFormat(const gl::ImageIndex & index) const1765 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1766 {
1767     return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1768 }
1769 
hasEmulatedAlphaChannel(const gl::ImageIndex & index) const1770 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1771 {
1772     return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1773         .emulatedAlphaChannel;
1774 }
1775 
recreateTexture(const gl::Context * context)1776 angle::Result TextureGL::recreateTexture(const gl::Context *context)
1777 {
1778     const FunctionsGL *functions = GetFunctionsGL(context);
1779     StateManagerGL *stateManager = GetStateManagerGL(context);
1780 
1781     stateManager->bindTexture(getType(), mTextureID);
1782     stateManager->deleteTexture(mTextureID);
1783 
1784     functions->genTextures(1, &mTextureID);
1785     stateManager->bindTexture(getType(), mTextureID);
1786 
1787     mLevelInfo.clear();
1788     mLevelInfo.resize(GetMaxLevelInfoCountForTextureType(getType()));
1789 
1790     mAppliedSwizzle = gl::SwizzleState();
1791     mAppliedSampler = gl::SamplerState::CreateDefaultForTarget(getType());
1792 
1793     mAppliedBaseLevel = 0;
1794     mAppliedBaseLevel = gl::kInitialMaxLevel;
1795 
1796     mLocalDirtyBits = mAllModifiedDirtyBits;
1797 
1798     onStateChange(angle::SubjectMessage::SubjectChanged);
1799 
1800     return angle::Result::Continue;
1801 }
1802 
syncTextureStateSwizzle(const gl::Context * context,const FunctionsGL * functions,GLenum name,GLenum value,GLenum * outValue)1803 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
1804                                                  const FunctionsGL *functions,
1805                                                  GLenum name,
1806                                                  GLenum value,
1807                                                  GLenum *outValue)
1808 {
1809     const LevelInfoGL &levelInfo = getBaseLevelInfo();
1810     GLenum resultSwizzle         = value;
1811     if (levelInfo.lumaWorkaround.enabled)
1812     {
1813         switch (value)
1814         {
1815             case GL_RED:
1816             case GL_GREEN:
1817             case GL_BLUE:
1818                 if (levelInfo.sourceFormat == GL_LUMINANCE ||
1819                     levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1820                 {
1821                     // Texture is backed by a RED or RG texture, point all color channels at the
1822                     // red channel.
1823                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
1824                            levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1825                     resultSwizzle = GL_RED;
1826                 }
1827                 else
1828                 {
1829                     ASSERT(levelInfo.sourceFormat == GL_ALPHA);
1830                     // Color channels are not supposed to exist, make them always sample 0.
1831                     resultSwizzle = GL_ZERO;
1832                 }
1833                 break;
1834 
1835             case GL_ALPHA:
1836                 if (levelInfo.sourceFormat == GL_LUMINANCE)
1837                 {
1838                     // Alpha channel is not supposed to exist, make it always sample 1.
1839                     resultSwizzle = GL_ONE;
1840                 }
1841                 else if (levelInfo.sourceFormat == GL_ALPHA)
1842                 {
1843                     // Texture is backed by a RED texture, point the alpha channel at the red
1844                     // channel.
1845                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1846                     resultSwizzle = GL_RED;
1847                 }
1848                 else
1849                 {
1850                     ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
1851                     // Texture is backed by an RG texture, point the alpha channel at the green
1852                     // channel.
1853                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1854                     resultSwizzle = GL_GREEN;
1855                 }
1856                 break;
1857 
1858             case GL_ZERO:
1859             case GL_ONE:
1860                 // Don't modify the swizzle state when requesting ZERO or ONE.
1861                 resultSwizzle = value;
1862                 break;
1863 
1864             default:
1865                 UNREACHABLE();
1866                 break;
1867         }
1868     }
1869     else if (levelInfo.depthStencilWorkaround)
1870     {
1871         switch (value)
1872         {
1873             case GL_RED:
1874                 // Don't modify the swizzle state when requesting the red channel.
1875                 resultSwizzle = value;
1876                 break;
1877 
1878             case GL_GREEN:
1879             case GL_BLUE:
1880                 if (context->getClientMajorVersion() <= 2)
1881                 {
1882                     // In OES_depth_texture/ARB_depth_texture, depth
1883                     // textures are treated as luminance.
1884                     resultSwizzle = GL_RED;
1885                 }
1886                 else
1887                 {
1888                     // In GLES 3.0, depth textures are treated as RED
1889                     // textures, so green and blue should be 0.
1890                     resultSwizzle = GL_ZERO;
1891                 }
1892                 break;
1893 
1894             case GL_ALPHA:
1895                 // Depth textures should sample 1 from the alpha channel.
1896                 resultSwizzle = GL_ONE;
1897                 break;
1898 
1899             case GL_ZERO:
1900             case GL_ONE:
1901                 // Don't modify the swizzle state when requesting ZERO or ONE.
1902                 resultSwizzle = value;
1903                 break;
1904 
1905             default:
1906                 UNREACHABLE();
1907                 break;
1908         }
1909     }
1910     else if (levelInfo.emulatedAlphaChannel)
1911     {
1912         if (value == GL_ALPHA)
1913         {
1914             resultSwizzle = GL_ONE;
1915         }
1916     }
1917 
1918     *outValue = resultSwizzle;
1919     ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
1920 
1921     return angle::Result::Continue;
1922 }
1923 
setLevelInfo(const gl::Context * context,gl::TextureTarget target,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1924 void TextureGL::setLevelInfo(const gl::Context *context,
1925                              gl::TextureTarget target,
1926                              size_t level,
1927                              size_t levelCount,
1928                              const LevelInfoGL &levelInfo)
1929 {
1930     ASSERT(levelCount > 0);
1931 
1932     bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
1933                              levelInfo.emulatedAlphaChannel;
1934 
1935     for (size_t i = level; i < level + levelCount; i++)
1936     {
1937         size_t index = GetLevelInfoIndex(target, i);
1938         ASSERT(index < mLevelInfo.size());
1939         auto &curLevelInfo = mLevelInfo[index];
1940 
1941         updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
1942         updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
1943         updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
1944 
1945         curLevelInfo = levelInfo;
1946     }
1947 
1948     if (updateWorkarounds)
1949     {
1950         mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1951         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1952     }
1953 }
1954 
setLevelInfo(const gl::Context * context,gl::TextureType type,size_t level,size_t levelCount,const LevelInfoGL & levelInfo)1955 void TextureGL::setLevelInfo(const gl::Context *context,
1956                              gl::TextureType type,
1957                              size_t level,
1958                              size_t levelCount,
1959                              const LevelInfoGL &levelInfo)
1960 {
1961     if (type == gl::TextureType::CubeMap)
1962     {
1963         for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
1964         {
1965             setLevelInfo(context, target, level, levelCount, levelInfo);
1966         }
1967     }
1968     else
1969     {
1970         setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
1971     }
1972 }
1973 
getLevelInfo(gl::TextureTarget target,size_t level) const1974 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
1975 {
1976     return mLevelInfo[GetLevelInfoIndex(target, level)];
1977 }
1978 
getBaseLevelInfo() const1979 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
1980 {
1981     GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1982     gl::TextureTarget target = getType() == gl::TextureType::CubeMap
1983                                    ? gl::kCubeMapTextureTargetMin
1984                                    : gl::NonCubeTextureTypeToTarget(getType());
1985     return getLevelInfo(target, effectiveBaseLevel);
1986 }
1987 
getType() const1988 gl::TextureType TextureGL::getType() const
1989 {
1990     return mState.getType();
1991 }
1992 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1993 angle::Result TextureGL::initializeContents(const gl::Context *context,
1994                                             const gl::ImageIndex &imageIndex)
1995 {
1996     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1997     const FunctionsGL *functions      = GetFunctionsGL(context);
1998     StateManagerGL *stateManager      = GetStateManagerGL(context);
1999     const angle::FeaturesGL &features = GetFeaturesGL(context);
2000 
2001     bool shouldUseClear = !nativegl::SupportsTexImage(getType());
2002     GLenum nativeInternalFormat =
2003         getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
2004     if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
2005         nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
2006     {
2007         BlitGL *blitter = GetBlitGL(context);
2008 
2009         int levelDepth = mState.getImageDesc(imageIndex).size.depth;
2010 
2011         bool clearSucceeded = false;
2012         ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
2013                                                   imageIndex, &clearSucceeded));
2014         if (clearSucceeded)
2015         {
2016             return angle::Result::Continue;
2017         }
2018     }
2019 
2020     // Either the texture is not renderable or was incomplete when clearing, fall back to a data
2021     // upload
2022     ASSERT(nativegl::SupportsTexImage(getType()));
2023     const gl::ImageDesc &desc                    = mState.getImageDesc(imageIndex);
2024     const gl::InternalFormat &internalFormatInfo = *desc.format.info;
2025 
2026     gl::PixelUnpackState unpackState;
2027     unpackState.alignment = 1;
2028     ANGLE_TRY(stateManager->setPixelUnpackState(context, unpackState));
2029 
2030     GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
2031     stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
2032 
2033     stateManager->bindTexture(getType(), mTextureID);
2034     if (internalFormatInfo.compressed)
2035     {
2036         nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
2037             nativegl::GetCompressedSubTexImageFormat(functions, features,
2038                                                      internalFormatInfo.internalFormat);
2039 
2040         GLuint imageSize = 0;
2041         ANGLE_CHECK_GL_MATH(contextGL,
2042                             internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
2043 
2044         angle::MemoryBuffer *zero;
2045         ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2046 
2047         // WebGL spec requires that zero data is uploaded to compressed textures even if it might
2048         // not result in zero color data.
2049         if (nativegl::UseTexImage2D(getType()))
2050         {
2051             ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
2052                                       ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2053                                       0, 0, desc.size.width, desc.size.height,
2054                                       nativeSubImageFormat.format, imageSize, zero->data()));
2055         }
2056         else
2057         {
2058             ASSERT(nativegl::UseTexImage3D(getType()));
2059             ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
2060                                       ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
2061                                       0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
2062                                       nativeSubImageFormat.format, imageSize, zero->data()));
2063         }
2064     }
2065     else
2066     {
2067         nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
2068             functions, features, internalFormatInfo.format, internalFormatInfo.type);
2069 
2070         GLuint imageSize = 0;
2071         ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
2072                                            nativeSubImageFormat.type, desc.size, unpackState,
2073                                            nativegl::UseTexImage3D(getType()), &imageSize));
2074 
2075         angle::MemoryBuffer *zero;
2076         ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
2077 
2078         if (nativegl::UseTexImage2D(getType()))
2079         {
2080             if (features.uploadTextureDataInChunks.enabled)
2081             {
2082                 gl::Box area(0, 0, 0, desc.size.width, desc.size.height, 1);
2083                 ANGLE_TRY(setSubImageRowByRowWorkaround(
2084                     context, imageIndex.getTarget(), imageIndex.getLevelIndex(), area,
2085                     nativeSubImageFormat.format, nativeSubImageFormat.type, unpackState, nullptr,
2086                     angle::FeaturesGL::kUploadTextureDataInChunksUploadSize, zero->data()));
2087             }
2088             else
2089             {
2090                 ANGLE_GL_TRY(context,
2091                              functions->texSubImage2D(
2092                                  ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0,
2093                                  desc.size.width, desc.size.height, nativeSubImageFormat.format,
2094                                  nativeSubImageFormat.type, zero->data()));
2095             }
2096         }
2097         else
2098         {
2099             ASSERT(nativegl::UseTexImage3D(getType()));
2100             ANGLE_GL_TRY(context,
2101                          functions->texSubImage3D(
2102                              ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
2103                              desc.size.width, desc.size.height, desc.size.depth,
2104                              nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
2105         }
2106     }
2107 
2108     // Reset the pixel unpack state.  Because this call is made after synchronizing dirty bits in a
2109     // glTexImage call, we need to make sure that the texture data to be uploaded later has the
2110     // expected unpack state.
2111     ANGLE_TRY(stateManager->setPixelUnpackState(context, context->getState().getUnpackState()));
2112     stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
2113 
2114     return angle::Result::Continue;
2115 }
2116 
getRequiredExternalTextureImageUnits(const gl::Context * context)2117 GLint TextureGL::getRequiredExternalTextureImageUnits(const gl::Context *context)
2118 {
2119     const FunctionsGL *functions = GetFunctionsGL(context);
2120     StateManagerGL *stateManager = GetStateManagerGL(context);
2121 
2122     ASSERT(getType() == gl::TextureType::External);
2123     stateManager->bindTexture(getType(), mTextureID);
2124 
2125     GLint result = 0;
2126     functions->getTexParameteriv(ToGLenum(gl::NonCubeTextureTypeToTarget(getType())),
2127                                  GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES, &result);
2128     return result;
2129 }
2130 
2131 }  // namespace rx
2132