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