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