[ANGLE - iOS] fast/canvas/webgl/uninitialized-test.html is still failing
[WebKit-https.git] / Source / ThirdParty / ANGLE / src / libANGLE / renderer / gl / TextureGL.cpp
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
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
49 bool IsLUMAFormat(GLenum format)
50 {
51     return format == GL_LUMINANCE || format == GL_ALPHA || format == GL_LUMINANCE_ALPHA;
52 }
53
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
66 bool GetDepthStencilWorkaround(GLenum format)
67 {
68     return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL;
69 }
70
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
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
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
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
116 LUMAWorkaroundGL::LUMAWorkaroundGL() : LUMAWorkaroundGL(false, GL_NONE) {}
117
118 LUMAWorkaroundGL::LUMAWorkaroundGL(bool enabled_, GLenum workaroundFormat_)
119     : enabled(enabled_), workaroundFormat(workaroundFormat_)
120 {}
121
122 LevelInfoGL::LevelInfoGL() : LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(), false) {}
123
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
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
147 TextureGL::~TextureGL()
148 {
149     ASSERT(mTextureID == 0);
150 }
151
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
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
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
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
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
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
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
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
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
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 (features.emulateCopyTexImage2DFromRenderbuffers.enabled && readBuffer &&
717                 readBuffer->type() == GL_RENDERBUFFER)
718             {
719                 BlitGL *blitter = GetBlitGL(context);
720                 ANGLE_TRY(blitter->blitColorBufferWithShader(
721                     context, source, mTextureID, target, level, clippedArea,
722                     gl::Rectangle(destOffset.x, destOffset.y, clippedArea.width,
723                                   clippedArea.height),
724                     GL_NEAREST, true));
725             }
726             else if (requiresInitialization)
727             {
728                 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
729                                           ToGLenum(target), static_cast<GLint>(level), destOffset.x,
730                                           destOffset.y, clippedArea.x, clippedArea.y,
731                                           clippedArea.width, clippedArea.height));
732             }
733             else
734             {
735                 ANGLE_GL_TRY_ALWAYS_CHECK(
736                     context, functions->copyTexImage2D(ToGLenum(target), static_cast<GLint>(level),
737                                                        copyTexImageFormat.internalFormat,
738                                                        clippedArea.x, clippedArea.y,
739                                                        clippedArea.width, clippedArea.height, 0));
740             }
741         }
742         setLevelInfo(context, target, level, 1, levelInfo);
743     }
744
745     if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
746     {
747         contextGL->setNeedsFlushBeforeDeleteTextures();
748     }
749
750     return angle::Result::Continue;
751 }
752
753 angle::Result TextureGL::copySubImage(const gl::Context *context,
754                                       const gl::ImageIndex &index,
755                                       const gl::Offset &destOffset,
756                                       const gl::Rectangle &sourceArea,
757                                       gl::Framebuffer *source)
758 {
759     const FunctionsGL *functions      = GetFunctionsGL(context);
760     StateManagerGL *stateManager      = GetStateManagerGL(context);
761     const angle::FeaturesGL &features = GetFeaturesGL(context);
762
763     gl::TextureTarget target                 = index.getTarget();
764     size_t level                             = static_cast<size_t>(index.getLevelIndex());
765     const FramebufferGL *sourceFramebufferGL = GetImplAs<FramebufferGL>(source);
766
767     // Clip source area to framebuffer.
768     const gl::Extents fbSize = sourceFramebufferGL->getState().getReadAttachment()->getSize();
769     gl::Rectangle clippedArea;
770     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
771     {
772         // nothing to do
773         return angle::Result::Continue;
774     }
775     gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
776                              destOffset.y + clippedArea.y - sourceArea.y, destOffset.z);
777
778     stateManager->bindTexture(getType(), mTextureID);
779     stateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, sourceFramebufferGL->getFramebufferID());
780
781     const LevelInfoGL &levelInfo = getLevelInfo(target, level);
782     if (levelInfo.lumaWorkaround.enabled)
783     {
784         BlitGL *blitter = GetBlitGL(context);
785         ANGLE_TRY(blitter->copySubImageToLUMAWorkaroundTexture(
786             context, mTextureID, getType(), target, levelInfo.sourceFormat, level, clippedOffset,
787             clippedArea, source));
788     }
789     else
790     {
791         if (nativegl::UseTexImage2D(getType()))
792         {
793             ASSERT(clippedOffset.z == 0);
794             if (features.emulateCopyTexImage2DFromRenderbuffers.enabled &&
795                 source->getReadColorAttachment() &&
796                 source->getReadColorAttachment()->type() == GL_RENDERBUFFER)
797             {
798                 BlitGL *blitter = GetBlitGL(context);
799                 ANGLE_TRY(blitter->blitColorBufferWithShader(
800                     context, source, mTextureID, target, level, clippedArea,
801                     gl::Rectangle(clippedOffset.x, clippedOffset.y, clippedArea.width,
802                                   clippedArea.height),
803                     GL_NEAREST, true));
804             }
805             else
806             {
807                 ANGLE_GL_TRY(context, functions->copyTexSubImage2D(
808                                           ToGLenum(target), static_cast<GLint>(level),
809                                           clippedOffset.x, clippedOffset.y, clippedArea.x,
810                                           clippedArea.y, clippedArea.width, clippedArea.height));
811             }
812         }
813         else
814         {
815             ASSERT(nativegl::UseTexImage3D(getType()));
816             ANGLE_GL_TRY(context, functions->copyTexSubImage3D(
817                                       ToGLenum(target), static_cast<GLint>(level), clippedOffset.x,
818                                       clippedOffset.y, clippedOffset.z, clippedArea.x,
819                                       clippedArea.y, clippedArea.width, clippedArea.height));
820         }
821     }
822
823     if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
824     {
825         ContextGL *contextGL = GetImplAs<ContextGL>(context);
826         contextGL->setNeedsFlushBeforeDeleteTextures();
827     }
828
829     return angle::Result::Continue;
830 }
831
832 angle::Result TextureGL::copyTexture(const gl::Context *context,
833                                      const gl::ImageIndex &index,
834                                      GLenum internalFormat,
835                                      GLenum type,
836                                      size_t sourceLevel,
837                                      bool unpackFlipY,
838                                      bool unpackPremultiplyAlpha,
839                                      bool unpackUnmultiplyAlpha,
840                                      const gl::Texture *source)
841 {
842     gl::TextureTarget target  = index.getTarget();
843     size_t level              = static_cast<size_t>(index.getLevelIndex());
844     const TextureGL *sourceGL = GetImplAs<TextureGL>(source);
845     const gl::ImageDesc &sourceImageDesc =
846         sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
847     gl::Rectangle sourceArea(0, 0, sourceImageDesc.size.width, sourceImageDesc.size.height);
848
849     ANGLE_TRY(reserveTexImageToBeFilled(context, target, level, internalFormat,
850                                         sourceImageDesc.size, gl::GetUnsizedFormat(internalFormat),
851                                         type));
852
853     const gl::InternalFormat &destFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
854     return copySubTextureHelper(context, target, level, gl::Offset(0, 0, 0), sourceLevel,
855                                 sourceArea, destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
856                                 unpackUnmultiplyAlpha, source);
857 }
858
859 angle::Result TextureGL::copySubTexture(const gl::Context *context,
860                                         const gl::ImageIndex &index,
861                                         const gl::Offset &destOffset,
862                                         size_t sourceLevel,
863                                         const gl::Box &sourceBox,
864                                         bool unpackFlipY,
865                                         bool unpackPremultiplyAlpha,
866                                         bool unpackUnmultiplyAlpha,
867                                         const gl::Texture *source)
868 {
869     gl::TextureTarget target                 = index.getTarget();
870     size_t level                             = static_cast<size_t>(index.getLevelIndex());
871     const gl::InternalFormat &destFormatInfo = *mState.getImageDesc(target, level).format.info;
872     return copySubTextureHelper(context, target, level, destOffset, sourceLevel, sourceBox.toRect(),
873                                 destFormatInfo, unpackFlipY, unpackPremultiplyAlpha,
874                                 unpackUnmultiplyAlpha, source);
875 }
876
877 angle::Result TextureGL::copySubTextureHelper(const gl::Context *context,
878                                               gl::TextureTarget target,
879                                               size_t level,
880                                               const gl::Offset &destOffset,
881                                               size_t sourceLevel,
882                                               const gl::Rectangle &sourceArea,
883                                               const gl::InternalFormat &destFormat,
884                                               bool unpackFlipY,
885                                               bool unpackPremultiplyAlpha,
886                                               bool unpackUnmultiplyAlpha,
887                                               const gl::Texture *source)
888 {
889     const FunctionsGL *functions      = GetFunctionsGL(context);
890     const angle::FeaturesGL &features = GetFeaturesGL(context);
891     BlitGL *blitter                   = GetBlitGL(context);
892
893     TextureGL *sourceGL = GetImplAs<TextureGL>(source);
894     const gl::ImageDesc &sourceImageDesc =
895         sourceGL->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
896
897     if (features.flushBeforeDeleteTextureIfCopiedTo.enabled)
898     {
899         // Conservatively indicate that this workaround is necessary. Not clear
900         // if it is on this code path, but added for symmetry.
901         ContextGL *contextGL = GetImplAs<ContextGL>(context);
902         contextGL->setNeedsFlushBeforeDeleteTextures();
903     }
904
905     // Check is this is a simple copySubTexture that can be done with a copyTexSubImage
906     ASSERT(sourceGL->getType() == gl::TextureType::_2D ||
907            source->getType() == gl::TextureType::External ||
908            source->getType() == gl::TextureType::Rectangle);
909     const LevelInfoGL &sourceLevelInfo =
910         sourceGL->getLevelInfo(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
911     bool needsLumaWorkaround = sourceLevelInfo.lumaWorkaround.enabled;
912
913     const gl::InternalFormat &sourceFormatInfo = *sourceImageDesc.format.info;
914     GLenum sourceFormat                        = sourceFormatInfo.format;
915     bool sourceFormatContainSupersetOfDestFormat =
916         (sourceFormat == destFormat.format && sourceFormat != GL_BGRA_EXT) ||
917         (sourceFormat == GL_RGBA && destFormat.format == GL_RGB);
918
919     GLenum sourceComponentType = sourceFormatInfo.componentType;
920     GLenum destComponentType   = destFormat.componentType;
921     bool destSRGB              = destFormat.colorEncoding == GL_SRGB;
922     if (!unpackFlipY && unpackPremultiplyAlpha == unpackUnmultiplyAlpha && !needsLumaWorkaround &&
923         sourceFormatContainSupersetOfDestFormat && sourceComponentType == destComponentType &&
924         !destSRGB && sourceGL->getType() == gl::TextureType::_2D)
925     {
926         bool copySucceeded = false;
927         ANGLE_TRY(blitter->copyTexSubImage(context, sourceGL, sourceLevel, this, target, level,
928                                            sourceArea, destOffset, &copySucceeded));
929         if (copySucceeded)
930         {
931             return angle::Result::Continue;
932         }
933     }
934
935     // Check if the destination is renderable and copy on the GPU
936     const LevelInfoGL &destLevelInfo = getLevelInfo(target, level);
937     // todo(jonahr): http://crbug.com/773861
938     // Behavior for now is to fallback to CPU readback implementation if the destination texture
939     // is a luminance format. The correct solution is to handle both source and destination in the
940     // luma workaround.
941     if (!destSRGB && !destLevelInfo.lumaWorkaround.enabled &&
942         nativegl::SupportsNativeRendering(functions, getType(), destLevelInfo.nativeInternalFormat))
943     {
944         bool copySucceeded = false;
945         ANGLE_TRY(blitter->copySubTexture(
946             context, sourceGL, sourceLevel, sourceComponentType, mTextureID, target, level,
947             destComponentType, sourceImageDesc.size, sourceArea, destOffset, needsLumaWorkaround,
948             sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
949             unpackUnmultiplyAlpha, &copySucceeded));
950         if (copySucceeded)
951         {
952             return angle::Result::Continue;
953         }
954     }
955
956     // Fall back to CPU-readback
957     return blitter->copySubTextureCPUReadback(
958         context, sourceGL, sourceLevel, sourceFormatInfo.sizedInternalFormat, this, target, level,
959         destFormat.format, destFormat.type, sourceImageDesc.size, sourceArea, destOffset,
960         needsLumaWorkaround, sourceLevelInfo.sourceFormat, unpackFlipY, unpackPremultiplyAlpha,
961         unpackUnmultiplyAlpha);
962 }
963
964 angle::Result TextureGL::setStorage(const gl::Context *context,
965                                     gl::TextureType type,
966                                     size_t levels,
967                                     GLenum internalFormat,
968                                     const gl::Extents &size)
969 {
970     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
971     const FunctionsGL *functions      = GetFunctionsGL(context);
972     StateManagerGL *stateManager      = GetStateManagerGL(context);
973     const angle::FeaturesGL &features = GetFeaturesGL(context);
974
975     nativegl::TexStorageFormat texStorageFormat =
976         nativegl::GetTexStorageFormat(functions, features, internalFormat);
977
978     stateManager->bindTexture(getType(), mTextureID);
979     if (nativegl::UseTexImage2D(getType()))
980     {
981         ASSERT(size.depth == 1);
982         if (functions->texStorage2D)
983         {
984             ANGLE_GL_TRY_ALWAYS_CHECK(
985                 context,
986                 functions->texStorage2D(ToGLenum(type), static_cast<GLsizei>(levels),
987                                         texStorageFormat.internalFormat, size.width, size.height));
988         }
989         else
990         {
991             // Make sure no pixel unpack buffer is bound
992             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
993
994             const gl::InternalFormat &internalFormatInfo =
995                 gl::GetSizedInternalFormatInfo(internalFormat);
996
997             // Internal format must be sized
998             ASSERT(internalFormatInfo.sized);
999
1000             for (size_t level = 0; level < levels; level++)
1001             {
1002                 gl::Extents levelSize(std::max(size.width >> level, 1),
1003                                       std::max(size.height >> level, 1), 1);
1004
1005                 if (getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle)
1006                 {
1007                     if (internalFormatInfo.compressed)
1008                     {
1009                         nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1010                             nativegl::GetCompressedSubTexImageFormat(functions, features,
1011                                                                      internalFormat);
1012
1013                         GLuint dataSize = 0;
1014                         ANGLE_CHECK_GL_MATH(
1015                             contextGL,
1016                             internalFormatInfo.computeCompressedImageSize(levelSize, &dataSize));
1017                         ANGLE_GL_TRY_ALWAYS_CHECK(
1018                             context,
1019                             functions->compressedTexImage2D(
1020                                 ToGLenum(type), static_cast<GLint>(level),
1021                                 compressedTexImageFormat.format, levelSize.width, levelSize.height,
1022                                 0, static_cast<GLsizei>(dataSize), nullptr));
1023                     }
1024                     else
1025                     {
1026                         nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1027                             functions, features, internalFormat, internalFormatInfo.format,
1028                             internalFormatInfo.type);
1029
1030                         ANGLE_GL_TRY_ALWAYS_CHECK(
1031                             context,
1032                             functions->texImage2D(ToGLenum(type), static_cast<GLint>(level),
1033                                                   texImageFormat.internalFormat, levelSize.width,
1034                                                   levelSize.height, 0, texImageFormat.format,
1035                                                   texImageFormat.type, nullptr));
1036                     }
1037                 }
1038                 else
1039                 {
1040                     ASSERT(getType() == gl::TextureType::CubeMap);
1041                     for (gl::TextureTarget face : gl::AllCubeFaceTextureTargets())
1042                     {
1043                         if (internalFormatInfo.compressed)
1044                         {
1045                             nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1046                                 nativegl::GetCompressedSubTexImageFormat(functions, features,
1047                                                                          internalFormat);
1048
1049                             GLuint dataSize = 0;
1050                             ANGLE_CHECK_GL_MATH(contextGL,
1051                                                 internalFormatInfo.computeCompressedImageSize(
1052                                                     levelSize, &dataSize));
1053                             ANGLE_GL_TRY_ALWAYS_CHECK(
1054                                 context,
1055                                 functions->compressedTexImage2D(
1056                                     ToGLenum(face), static_cast<GLint>(level),
1057                                     compressedTexImageFormat.format, levelSize.width,
1058                                     levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr));
1059                         }
1060                         else
1061                         {
1062                             nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1063                                 functions, features, internalFormat, internalFormatInfo.format,
1064                                 internalFormatInfo.type);
1065
1066                             ANGLE_GL_TRY_ALWAYS_CHECK(
1067                                 context, functions->texImage2D(
1068                                              ToGLenum(face), static_cast<GLint>(level),
1069                                              texImageFormat.internalFormat, levelSize.width,
1070                                              levelSize.height, 0, texImageFormat.format,
1071                                              texImageFormat.type, nullptr));
1072                         }
1073                     }
1074                 }
1075             }
1076         }
1077     }
1078     else
1079     {
1080         ASSERT(nativegl::UseTexImage3D(getType()));
1081         if (functions->texStorage3D)
1082         {
1083             ANGLE_GL_TRY_ALWAYS_CHECK(
1084                 context, functions->texStorage3D(ToGLenum(type), static_cast<GLsizei>(levels),
1085                                                  texStorageFormat.internalFormat, size.width,
1086                                                  size.height, size.depth));
1087         }
1088         else
1089         {
1090             // Make sure no pixel unpack buffer is bound
1091             stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1092
1093             const gl::InternalFormat &internalFormatInfo =
1094                 gl::GetSizedInternalFormatInfo(internalFormat);
1095
1096             // Internal format must be sized
1097             ASSERT(internalFormatInfo.sized);
1098
1099             for (GLsizei i = 0; i < static_cast<GLsizei>(levels); i++)
1100             {
1101                 gl::Extents levelSize(
1102                     std::max(size.width >> i, 1), std::max(size.height >> i, 1),
1103                     getType() == gl::TextureType::_3D ? std::max(size.depth >> i, 1) : size.depth);
1104
1105                 if (internalFormatInfo.compressed)
1106                 {
1107                     nativegl::CompressedTexSubImageFormat compressedTexImageFormat =
1108                         nativegl::GetCompressedSubTexImageFormat(functions, features,
1109                                                                  internalFormat);
1110
1111                     GLuint dataSize = 0;
1112                     ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computeCompressedImageSize(
1113                                                        levelSize, &dataSize));
1114                     ANGLE_GL_TRY_ALWAYS_CHECK(
1115                         context, functions->compressedTexImage3D(
1116                                      ToGLenum(type), i, compressedTexImageFormat.format,
1117                                      levelSize.width, levelSize.height, levelSize.depth, 0,
1118                                      static_cast<GLsizei>(dataSize), nullptr));
1119                 }
1120                 else
1121                 {
1122                     nativegl::TexImageFormat texImageFormat = nativegl::GetTexImageFormat(
1123                         functions, features, internalFormat, internalFormatInfo.format,
1124                         internalFormatInfo.type);
1125
1126                     ANGLE_GL_TRY_ALWAYS_CHECK(
1127                         context,
1128                         functions->texImage3D(ToGLenum(type), i, texImageFormat.internalFormat,
1129                                               levelSize.width, levelSize.height, levelSize.depth, 0,
1130                                               texImageFormat.format, texImageFormat.type, nullptr));
1131                 }
1132             }
1133         }
1134     }
1135
1136     setLevelInfo(context, type, 0, levels,
1137                  GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1138
1139     return angle::Result::Continue;
1140 }
1141
1142 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1143                                           const gl::ImageIndex &index,
1144                                           GLenum internalFormat,
1145                                           const gl::Extents &size,
1146                                           GLenum format,
1147                                           GLenum type)
1148 {
1149     const FunctionsGL *functions      = GetFunctionsGL(context);
1150     const angle::FeaturesGL &features = GetFeaturesGL(context);
1151
1152     gl::TextureTarget target = index.getTarget();
1153     size_t level             = static_cast<size_t>(index.getLevelIndex());
1154     nativegl::TexImageFormat texImageFormat =
1155         nativegl::GetTexImageFormat(functions, features, internalFormat, format, type);
1156
1157     setLevelInfo(context, target, level, 1,
1158                  GetLevelInfo(features, internalFormat, texImageFormat.internalFormat));
1159     return angle::Result::Continue;
1160 }
1161
1162 angle::Result TextureGL::setStorageMultisample(const gl::Context *context,
1163                                                gl::TextureType type,
1164                                                GLsizei samples,
1165                                                GLint internalformat,
1166                                                const gl::Extents &size,
1167                                                bool fixedSampleLocations)
1168 {
1169     const FunctionsGL *functions      = GetFunctionsGL(context);
1170     StateManagerGL *stateManager      = GetStateManagerGL(context);
1171     const angle::FeaturesGL &features = GetFeaturesGL(context);
1172
1173     nativegl::TexStorageFormat texStorageFormat =
1174         nativegl::GetTexStorageFormat(functions, features, internalformat);
1175
1176     stateManager->bindTexture(getType(), mTextureID);
1177
1178     if (nativegl::UseTexImage2D(getType()))
1179     {
1180         ASSERT(size.depth == 1);
1181         if (functions->texStorage2DMultisample)
1182         {
1183             ANGLE_GL_TRY_ALWAYS_CHECK(
1184                 context, functions->texStorage2DMultisample(
1185                              ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1186                              size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1187         }
1188         else
1189         {
1190             // texImage2DMultisample is similar to texStorage2DMultisample of es 3.1 core feature,
1191             // On macos and some old drivers which doesn't support OpenGL ES 3.1, the function can
1192             // be supported by ARB_texture_multisample or OpenGL 3.2 core feature.
1193             ANGLE_GL_TRY_ALWAYS_CHECK(
1194                 context, functions->texImage2DMultisample(
1195                              ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1196                              size.height, gl::ConvertToGLBoolean(fixedSampleLocations)));
1197         }
1198     }
1199     else
1200     {
1201         ASSERT(nativegl::UseTexImage3D(getType()));
1202         ANGLE_GL_TRY_ALWAYS_CHECK(
1203             context, functions->texStorage3DMultisample(
1204                          ToGLenum(type), samples, texStorageFormat.internalFormat, size.width,
1205                          size.height, size.depth, gl::ConvertToGLBoolean(fixedSampleLocations)));
1206     }
1207
1208     setLevelInfo(context, type, 0, 1,
1209                  GetLevelInfo(features, internalformat, texStorageFormat.internalFormat));
1210
1211     return angle::Result::Continue;
1212 }
1213
1214 angle::Result TextureGL::setStorageExternalMemory(const gl::Context *context,
1215                                                   gl::TextureType type,
1216                                                   size_t levels,
1217                                                   GLenum internalFormat,
1218                                                   const gl::Extents &size,
1219                                                   gl::MemoryObject *memoryObject,
1220                                                   GLuint64 offset)
1221 {
1222     const FunctionsGL *functions      = GetFunctionsGL(context);
1223     StateManagerGL *stateManager      = GetStateManagerGL(context);
1224     const angle::FeaturesGL &features = GetFeaturesGL(context);
1225
1226     MemoryObjectGL *memoryObjectGL = GetImplAs<MemoryObjectGL>(memoryObject);
1227
1228     nativegl::TexStorageFormat texStorageFormat =
1229         nativegl::GetTexStorageFormat(functions, features, internalFormat);
1230
1231     stateManager->bindTexture(getType(), mTextureID);
1232     if (nativegl::UseTexImage2D(getType()))
1233     {
1234         ANGLE_GL_TRY_ALWAYS_CHECK(
1235             context,
1236             functions->texStorageMem2DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1237                                           texStorageFormat.internalFormat, size.width, size.height,
1238                                           memoryObjectGL->getMemoryObjectID(), offset));
1239     }
1240     else
1241     {
1242         ASSERT(nativegl::UseTexImage3D(getType()));
1243         ANGLE_GL_TRY_ALWAYS_CHECK(
1244             context,
1245             functions->texStorageMem3DEXT(ToGLenum(type), static_cast<GLsizei>(levels),
1246                                           texStorageFormat.internalFormat, size.width, size.height,
1247                                           size.depth, memoryObjectGL->getMemoryObjectID(), offset));
1248     }
1249
1250     setLevelInfo(context, type, 0, levels,
1251                  GetLevelInfo(features, internalFormat, texStorageFormat.internalFormat));
1252
1253     return angle::Result::Continue;
1254 }
1255
1256 angle::Result TextureGL::setImageExternal(const gl::Context *context,
1257                                           gl::TextureType type,
1258                                           egl::Stream *stream,
1259                                           const egl::Stream::GLTextureDescription &desc)
1260 {
1261     ANGLE_GL_UNREACHABLE(GetImplAs<ContextGL>(context));
1262     return angle::Result::Stop;
1263 }
1264
1265 angle::Result TextureGL::generateMipmap(const gl::Context *context)
1266 {
1267     const FunctionsGL *functions = GetFunctionsGL(context);
1268     StateManagerGL *stateManager = GetStateManagerGL(context);
1269
1270     stateManager->bindTexture(getType(), mTextureID);
1271     ANGLE_GL_TRY_ALWAYS_CHECK(context, functions->generateMipmap(ToGLenum(getType())));
1272
1273     const GLuint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1274     const GLuint maxLevel           = mState.getMipmapMaxLevel();
1275
1276     setLevelInfo(context, getType(), effectiveBaseLevel, maxLevel - effectiveBaseLevel,
1277                  getBaseLevelInfo());
1278
1279     return angle::Result::Continue;
1280 }
1281
1282 angle::Result TextureGL::bindTexImage(const gl::Context *context, egl::Surface *surface)
1283 {
1284     ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1285
1286     StateManagerGL *stateManager = GetStateManagerGL(context);
1287
1288     // Make sure this texture is bound
1289     stateManager->bindTexture(getType(), mTextureID);
1290
1291     SurfaceGL *surfaceGL = GetImplAs<SurfaceGL>(surface);
1292
1293     setLevelInfo(context, getType(), 0, 1,
1294                  LevelInfoGL(GL_NONE, GL_NONE, false, LUMAWorkaroundGL(),
1295                              surfaceGL->hasEmulatedAlphaChannel()));
1296     return angle::Result::Continue;
1297 }
1298
1299 angle::Result TextureGL::releaseTexImage(const gl::Context *context)
1300 {
1301     ASSERT(getType() == gl::TextureType::_2D || getType() == gl::TextureType::Rectangle);
1302
1303     const angle::FeaturesGL &features = GetFeaturesGL(context);
1304     if (!features.resettingTexturesGeneratesErrors.enabled)
1305     {
1306         // Not all Surface implementations reset the size of mip 0 when releasing, do it manually
1307         const FunctionsGL *functions = GetFunctionsGL(context);
1308         StateManagerGL *stateManager = GetStateManagerGL(context);
1309
1310         stateManager->bindTexture(getType(), mTextureID);
1311         ASSERT(nativegl::UseTexImage2D(getType()));
1312         ANGLE_GL_TRY(context, functions->texImage2D(ToGLenum(getType()), 0, GL_RGBA, 0, 0, 0,
1313                                                     GL_RGBA, GL_UNSIGNED_BYTE, nullptr));
1314     }
1315
1316     return angle::Result::Continue;
1317 }
1318
1319 angle::Result TextureGL::setEGLImageTarget(const gl::Context *context,
1320                                            gl::TextureType type,
1321                                            egl::Image *image)
1322 {
1323     const angle::FeaturesGL &features = GetFeaturesGL(context);
1324
1325     ImageGL *imageGL = GetImplAs<ImageGL>(image);
1326
1327     GLenum imageNativeInternalFormat = GL_NONE;
1328     ANGLE_TRY(imageGL->setTexture2D(context, type, this, &imageNativeInternalFormat));
1329
1330     setLevelInfo(
1331         context, type, 0, 1,
1332         GetLevelInfo(features, image->getFormat().info->internalFormat, imageNativeInternalFormat));
1333
1334     return angle::Result::Continue;
1335 }
1336
1337 GLint TextureGL::getNativeID() const
1338 {
1339     return mTextureID;
1340 }
1341
1342 angle::Result TextureGL::syncState(const gl::Context *context,
1343                                    const gl::Texture::DirtyBits &dirtyBits)
1344 {
1345     if (dirtyBits.none() && mLocalDirtyBits.none())
1346     {
1347         return angle::Result::Continue;
1348     }
1349
1350     const FunctionsGL *functions = GetFunctionsGL(context);
1351     StateManagerGL *stateManager = GetStateManagerGL(context);
1352
1353     stateManager->bindTexture(getType(), mTextureID);
1354
1355     if (dirtyBits[gl::Texture::DIRTY_BIT_BASE_LEVEL] || dirtyBits[gl::Texture::DIRTY_BIT_MAX_LEVEL])
1356     {
1357         // Don't know if the previous base level was using any workarounds, always re-sync the
1358         // workaround dirty bits
1359         mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1360     }
1361     for (auto dirtyBit : (dirtyBits | mLocalDirtyBits))
1362     {
1363
1364         switch (dirtyBit)
1365         {
1366             case gl::Texture::DIRTY_BIT_MIN_FILTER:
1367                 mAppliedSampler.setMinFilter(mState.getSamplerState().getMinFilter());
1368                 ANGLE_GL_TRY(context, functions->texParameteri(
1369                                           nativegl::GetTextureBindingTarget(getType()),
1370                                           GL_TEXTURE_MIN_FILTER, mAppliedSampler.getMinFilter()));
1371                 break;
1372             case gl::Texture::DIRTY_BIT_MAG_FILTER:
1373                 mAppliedSampler.setMagFilter(mState.getSamplerState().getMagFilter());
1374                 ANGLE_GL_TRY(context, functions->texParameteri(
1375                                           nativegl::GetTextureBindingTarget(getType()),
1376                                           GL_TEXTURE_MAG_FILTER, mAppliedSampler.getMagFilter()));
1377                 break;
1378             case gl::Texture::DIRTY_BIT_WRAP_S:
1379                 mAppliedSampler.setWrapS(mState.getSamplerState().getWrapS());
1380                 ANGLE_GL_TRY(context, functions->texParameteri(
1381                                           nativegl::GetTextureBindingTarget(getType()),
1382                                           GL_TEXTURE_WRAP_S, mAppliedSampler.getWrapS()));
1383                 break;
1384             case gl::Texture::DIRTY_BIT_WRAP_T:
1385                 mAppliedSampler.setWrapT(mState.getSamplerState().getWrapT());
1386                 ANGLE_GL_TRY(context, functions->texParameteri(
1387                                           nativegl::GetTextureBindingTarget(getType()),
1388                                           GL_TEXTURE_WRAP_T, mAppliedSampler.getWrapT()));
1389                 break;
1390             case gl::Texture::DIRTY_BIT_WRAP_R:
1391                 mAppliedSampler.setWrapR(mState.getSamplerState().getWrapR());
1392                 ANGLE_GL_TRY(context, functions->texParameteri(
1393                                           nativegl::GetTextureBindingTarget(getType()),
1394                                           GL_TEXTURE_WRAP_R, mAppliedSampler.getWrapR()));
1395                 break;
1396             case gl::Texture::DIRTY_BIT_MAX_ANISOTROPY:
1397                 mAppliedSampler.setMaxAnisotropy(mState.getSamplerState().getMaxAnisotropy());
1398                 ANGLE_GL_TRY(context,
1399                              functions->texParameterf(nativegl::GetTextureBindingTarget(getType()),
1400                                                       GL_TEXTURE_MAX_ANISOTROPY_EXT,
1401                                                       mAppliedSampler.getMaxAnisotropy()));
1402                 break;
1403             case gl::Texture::DIRTY_BIT_MIN_LOD:
1404                 mAppliedSampler.setMinLod(mState.getSamplerState().getMinLod());
1405                 ANGLE_GL_TRY(context, functions->texParameterf(
1406                                           nativegl::GetTextureBindingTarget(getType()),
1407                                           GL_TEXTURE_MIN_LOD, mAppliedSampler.getMinLod()));
1408                 break;
1409             case gl::Texture::DIRTY_BIT_MAX_LOD:
1410                 mAppliedSampler.setMaxLod(mState.getSamplerState().getMaxLod());
1411                 ANGLE_GL_TRY(context, functions->texParameterf(
1412                                           nativegl::GetTextureBindingTarget(getType()),
1413                                           GL_TEXTURE_MAX_LOD, mAppliedSampler.getMaxLod()));
1414                 break;
1415             case gl::Texture::DIRTY_BIT_COMPARE_MODE:
1416                 mAppliedSampler.setCompareMode(mState.getSamplerState().getCompareMode());
1417                 ANGLE_GL_TRY(context,
1418                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1419                                                       GL_TEXTURE_COMPARE_MODE,
1420                                                       mAppliedSampler.getCompareMode()));
1421                 break;
1422             case gl::Texture::DIRTY_BIT_COMPARE_FUNC:
1423                 mAppliedSampler.setCompareFunc(mState.getSamplerState().getCompareFunc());
1424                 ANGLE_GL_TRY(context,
1425                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1426                                                       GL_TEXTURE_COMPARE_FUNC,
1427                                                       mAppliedSampler.getCompareFunc()));
1428                 break;
1429             case gl::Texture::DIRTY_BIT_SRGB_DECODE:
1430                 mAppliedSampler.setSRGBDecode(mState.getSamplerState().getSRGBDecode());
1431                 ANGLE_GL_TRY(context,
1432                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1433                                                       GL_TEXTURE_SRGB_DECODE_EXT,
1434                                                       mAppliedSampler.getSRGBDecode()));
1435                 break;
1436             case gl::Texture::DIRTY_BIT_BORDER_COLOR:
1437             {
1438                 const angle::ColorGeneric &borderColor(mState.getSamplerState().getBorderColor());
1439                 mAppliedSampler.setBorderColor(borderColor);
1440                 switch (borderColor.type)
1441                 {
1442                     case angle::ColorGeneric::Type::Float:
1443                         ANGLE_GL_TRY(context,
1444                                      functions->texParameterfv(
1445                                          nativegl::GetTextureBindingTarget(getType()),
1446                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorF.red));
1447                         break;
1448                     case angle::ColorGeneric::Type::Int:
1449                         ANGLE_GL_TRY(context,
1450                                      functions->texParameterIiv(
1451                                          nativegl::GetTextureBindingTarget(getType()),
1452                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorI.red));
1453                         break;
1454                     case angle::ColorGeneric::Type::UInt:
1455                         ANGLE_GL_TRY(context,
1456                                      functions->texParameterIuiv(
1457                                          nativegl::GetTextureBindingTarget(getType()),
1458                                          GL_TEXTURE_BORDER_COLOR, &borderColor.colorUI.red));
1459                         break;
1460                     default:
1461                         UNREACHABLE();
1462                         break;
1463                 }
1464                 break;
1465             }
1466
1467             // Texture state
1468             case gl::Texture::DIRTY_BIT_SWIZZLE_RED:
1469                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_R,
1470                                                   mState.getSwizzleState().swizzleRed,
1471                                                   &mAppliedSwizzle.swizzleRed));
1472                 break;
1473             case gl::Texture::DIRTY_BIT_SWIZZLE_GREEN:
1474                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_G,
1475                                                   mState.getSwizzleState().swizzleGreen,
1476                                                   &mAppliedSwizzle.swizzleGreen));
1477                 break;
1478             case gl::Texture::DIRTY_BIT_SWIZZLE_BLUE:
1479                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_B,
1480                                                   mState.getSwizzleState().swizzleBlue,
1481                                                   &mAppliedSwizzle.swizzleBlue));
1482                 break;
1483             case gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA:
1484                 ANGLE_TRY(syncTextureStateSwizzle(context, functions, GL_TEXTURE_SWIZZLE_A,
1485                                                   mState.getSwizzleState().swizzleAlpha,
1486                                                   &mAppliedSwizzle.swizzleAlpha));
1487                 break;
1488             case gl::Texture::DIRTY_BIT_BASE_LEVEL:
1489                 mAppliedBaseLevel = mState.getEffectiveBaseLevel();
1490                 ANGLE_GL_TRY(context,
1491                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1492                                                       GL_TEXTURE_BASE_LEVEL, mAppliedBaseLevel));
1493                 break;
1494             case gl::Texture::DIRTY_BIT_MAX_LEVEL:
1495                 mAppliedMaxLevel = mState.getEffectiveMaxLevel();
1496                 ANGLE_GL_TRY(context,
1497                              functions->texParameteri(nativegl::GetTextureBindingTarget(getType()),
1498                                                       GL_TEXTURE_MAX_LEVEL, mAppliedMaxLevel));
1499                 break;
1500             case gl::Texture::DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE:
1501             {
1502                 GLenum mDepthStencilTextureMode = mState.getDepthStencilTextureMode();
1503                 ANGLE_GL_TRY(context, functions->texParameteri(
1504                                           nativegl::GetTextureBindingTarget(getType()),
1505                                           GL_DEPTH_STENCIL_TEXTURE_MODE, mDepthStencilTextureMode));
1506                 break;
1507             }
1508             case gl::Texture::DIRTY_BIT_USAGE:
1509                 break;
1510             case gl::Texture::DIRTY_BIT_LABEL:
1511                 break;
1512
1513             case gl::Texture::DIRTY_BIT_IMPLEMENTATION:
1514                 // This special dirty bit is used to signal the front-end that the implementation
1515                 // has local dirty bits. The real dirty bits are in mLocalDirty bits.
1516                 break;
1517             case gl::Texture::DIRTY_BIT_BOUND_AS_IMAGE:
1518                 // Only used for Vulkan.
1519                 break;
1520
1521             default:
1522                 UNREACHABLE();
1523         }
1524     }
1525
1526     mLocalDirtyBits.reset();
1527     return angle::Result::Continue;
1528 }
1529
1530 bool TextureGL::hasAnyDirtyBit() const
1531 {
1532     return mLocalDirtyBits.any();
1533 }
1534
1535 angle::Result TextureGL::setBaseLevel(const gl::Context *context, GLuint baseLevel)
1536 {
1537     if (baseLevel != mAppliedBaseLevel)
1538     {
1539         const FunctionsGL *functions = GetFunctionsGL(context);
1540         StateManagerGL *stateManager = GetStateManagerGL(context);
1541
1542         mAppliedBaseLevel = baseLevel;
1543         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_BASE_LEVEL);
1544
1545         // Signal to the GL layer that the Impl has dirty bits.
1546         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1547
1548         stateManager->bindTexture(getType(), mTextureID);
1549         ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_BASE_LEVEL,
1550                                                        baseLevel));
1551     }
1552     return angle::Result::Continue;
1553 }
1554
1555 angle::Result TextureGL::setMaxLevel(const gl::Context *context, GLuint maxLevel)
1556 {
1557     if (maxLevel != mAppliedMaxLevel)
1558     {
1559         const FunctionsGL *functions = GetFunctionsGL(context);
1560         StateManagerGL *stateManager = GetStateManagerGL(context);
1561
1562         mAppliedMaxLevel = maxLevel;
1563         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAX_LEVEL);
1564
1565         // Signal to the GL layer that the Impl has dirty bits.
1566         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1567
1568         stateManager->bindTexture(getType(), mTextureID);
1569         ANGLE_GL_TRY(context,
1570                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAX_LEVEL, maxLevel));
1571     }
1572     return angle::Result::Continue;
1573 }
1574
1575 angle::Result TextureGL::setMinFilter(const gl::Context *context, GLenum filter)
1576 {
1577     if (filter != mAppliedSampler.getMinFilter())
1578     {
1579         const FunctionsGL *functions = GetFunctionsGL(context);
1580         StateManagerGL *stateManager = GetStateManagerGL(context);
1581
1582         mAppliedSampler.setMinFilter(filter);
1583         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MIN_FILTER);
1584
1585         // Signal to the GL layer that the Impl has dirty bits.
1586         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1587
1588         stateManager->bindTexture(getType(), mTextureID);
1589         ANGLE_GL_TRY(context,
1590                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MIN_FILTER, filter));
1591     }
1592     return angle::Result::Continue;
1593 }
1594 angle::Result TextureGL::setMagFilter(const gl::Context *context, GLenum filter)
1595 {
1596     if (filter != mAppliedSampler.getMagFilter())
1597     {
1598         const FunctionsGL *functions = GetFunctionsGL(context);
1599         StateManagerGL *stateManager = GetStateManagerGL(context);
1600
1601         mAppliedSampler.setMagFilter(filter);
1602         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_MAG_FILTER);
1603
1604         // Signal to the GL layer that the Impl has dirty bits.
1605         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1606
1607         stateManager->bindTexture(getType(), mTextureID);
1608         ANGLE_GL_TRY(context,
1609                      functions->texParameteri(ToGLenum(getType()), GL_TEXTURE_MAG_FILTER, filter));
1610     }
1611     return angle::Result::Continue;
1612 }
1613
1614 angle::Result TextureGL::setSwizzle(const gl::Context *context, GLint swizzle[4])
1615 {
1616     gl::SwizzleState resultingSwizzle =
1617         gl::SwizzleState(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
1618
1619     if (resultingSwizzle != mAppliedSwizzle)
1620     {
1621         const FunctionsGL *functions = GetFunctionsGL(context);
1622         StateManagerGL *stateManager = GetStateManagerGL(context);
1623
1624         mAppliedSwizzle = resultingSwizzle;
1625         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_RED);
1626         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_GREEN);
1627         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_BLUE);
1628         mLocalDirtyBits.set(gl::Texture::DIRTY_BIT_SWIZZLE_ALPHA);
1629
1630         // Signal to the GL layer that the Impl has dirty bits.
1631         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1632
1633         stateManager->bindTexture(getType(), mTextureID);
1634         if (functions->standard == STANDARD_GL_ES)
1635         {
1636             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1637                                                            GL_TEXTURE_SWIZZLE_R, swizzle[0]));
1638             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1639                                                            GL_TEXTURE_SWIZZLE_G, swizzle[1]));
1640             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1641                                                            GL_TEXTURE_SWIZZLE_B, swizzle[2]));
1642             ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()),
1643                                                            GL_TEXTURE_SWIZZLE_A, swizzle[3]));
1644         }
1645         else
1646         {
1647             ANGLE_GL_TRY(context, functions->texParameteriv(ToGLenum(getType()),
1648                                                             GL_TEXTURE_SWIZZLE_RGBA, swizzle));
1649         }
1650     }
1651     return angle::Result::Continue;
1652 }
1653
1654 GLenum TextureGL::getNativeInternalFormat(const gl::ImageIndex &index) const
1655 {
1656     return getLevelInfo(index.getTarget(), index.getLevelIndex()).nativeInternalFormat;
1657 }
1658
1659 bool TextureGL::hasEmulatedAlphaChannel(const gl::ImageIndex &index) const
1660 {
1661     return getLevelInfo(index.getTargetOrFirstCubeFace(), index.getLevelIndex())
1662         .emulatedAlphaChannel;
1663 }
1664
1665 angle::Result TextureGL::syncTextureStateSwizzle(const gl::Context *context,
1666                                                  const FunctionsGL *functions,
1667                                                  GLenum name,
1668                                                  GLenum value,
1669                                                  GLenum *outValue)
1670 {
1671     const LevelInfoGL &levelInfo = getBaseLevelInfo();
1672     GLenum resultSwizzle         = value;
1673     if (levelInfo.lumaWorkaround.enabled)
1674     {
1675         switch (value)
1676         {
1677             case GL_RED:
1678             case GL_GREEN:
1679             case GL_BLUE:
1680                 if (levelInfo.sourceFormat == GL_LUMINANCE ||
1681                     levelInfo.sourceFormat == GL_LUMINANCE_ALPHA)
1682                 {
1683                     // Texture is backed by a RED or RG texture, point all color channels at the
1684                     // red channel.
1685                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED ||
1686                            levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1687                     resultSwizzle = GL_RED;
1688                 }
1689                 else
1690                 {
1691                     ASSERT(levelInfo.sourceFormat == GL_ALPHA);
1692                     // Color channels are not supposed to exist, make them always sample 0.
1693                     resultSwizzle = GL_ZERO;
1694                 }
1695                 break;
1696
1697             case GL_ALPHA:
1698                 if (levelInfo.sourceFormat == GL_LUMINANCE)
1699                 {
1700                     // Alpha channel is not supposed to exist, make it always sample 1.
1701                     resultSwizzle = GL_ONE;
1702                 }
1703                 else if (levelInfo.sourceFormat == GL_ALPHA)
1704                 {
1705                     // Texture is backed by a RED texture, point the alpha channel at the red
1706                     // channel.
1707                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RED);
1708                     resultSwizzle = GL_RED;
1709                 }
1710                 else
1711                 {
1712                     ASSERT(levelInfo.sourceFormat == GL_LUMINANCE_ALPHA);
1713                     // Texture is backed by an RG texture, point the alpha channel at the green
1714                     // channel.
1715                     ASSERT(levelInfo.lumaWorkaround.workaroundFormat == GL_RG);
1716                     resultSwizzle = GL_GREEN;
1717                 }
1718                 break;
1719
1720             case GL_ZERO:
1721             case GL_ONE:
1722                 // Don't modify the swizzle state when requesting ZERO or ONE.
1723                 resultSwizzle = value;
1724                 break;
1725
1726             default:
1727                 UNREACHABLE();
1728                 break;
1729         }
1730     }
1731     else if (levelInfo.depthStencilWorkaround)
1732     {
1733         switch (value)
1734         {
1735             case GL_RED:
1736                 // Don't modify the swizzle state when requesting the red channel.
1737                 resultSwizzle = value;
1738                 break;
1739
1740             case GL_GREEN:
1741             case GL_BLUE:
1742                 if (context->getClientMajorVersion() <= 2)
1743                 {
1744                     // In OES_depth_texture/ARB_depth_texture, depth
1745                     // textures are treated as luminance.
1746                     resultSwizzle = GL_RED;
1747                 }
1748                 else
1749                 {
1750                     // In GLES 3.0, depth textures are treated as RED
1751                     // textures, so green and blue should be 0.
1752                     resultSwizzle = GL_ZERO;
1753                 }
1754                 break;
1755
1756             case GL_ALPHA:
1757                 // Depth textures should sample 1 from the alpha channel.
1758                 resultSwizzle = GL_ONE;
1759                 break;
1760
1761             case GL_ZERO:
1762             case GL_ONE:
1763                 // Don't modify the swizzle state when requesting ZERO or ONE.
1764                 resultSwizzle = value;
1765                 break;
1766
1767             default:
1768                 UNREACHABLE();
1769                 break;
1770         }
1771     }
1772     else if (levelInfo.emulatedAlphaChannel)
1773     {
1774         if (value == GL_ALPHA)
1775         {
1776             resultSwizzle = GL_ONE;
1777         }
1778     }
1779
1780     *outValue = resultSwizzle;
1781     ANGLE_GL_TRY(context, functions->texParameteri(ToGLenum(getType()), name, resultSwizzle));
1782
1783     return angle::Result::Continue;
1784 }
1785
1786 void TextureGL::setLevelInfo(const gl::Context *context,
1787                              gl::TextureTarget target,
1788                              size_t level,
1789                              size_t levelCount,
1790                              const LevelInfoGL &levelInfo)
1791 {
1792     ASSERT(levelCount > 0);
1793
1794     bool updateWorkarounds = levelInfo.depthStencilWorkaround || levelInfo.lumaWorkaround.enabled ||
1795                              levelInfo.emulatedAlphaChannel;
1796
1797     for (size_t i = level; i < level + levelCount; i++)
1798     {
1799         size_t index = GetLevelInfoIndex(target, i);
1800         ASSERT(index < mLevelInfo.size());
1801         auto &curLevelInfo = mLevelInfo[index];
1802
1803         updateWorkarounds |= curLevelInfo.depthStencilWorkaround;
1804         updateWorkarounds |= curLevelInfo.lumaWorkaround.enabled;
1805         updateWorkarounds |= curLevelInfo.emulatedAlphaChannel;
1806
1807         curLevelInfo = levelInfo;
1808     }
1809
1810     if (updateWorkarounds)
1811     {
1812         mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
1813         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1814     }
1815 }
1816
1817 void TextureGL::setLevelInfo(const gl::Context *context,
1818                              gl::TextureType type,
1819                              size_t level,
1820                              size_t levelCount,
1821                              const LevelInfoGL &levelInfo)
1822 {
1823     if (type == gl::TextureType::CubeMap)
1824     {
1825         for (gl::TextureTarget target : gl::AllCubeFaceTextureTargets())
1826         {
1827             setLevelInfo(context, target, level, levelCount, levelInfo);
1828         }
1829     }
1830     else
1831     {
1832         setLevelInfo(context, NonCubeTextureTypeToTarget(type), level, levelCount, levelInfo);
1833     }
1834 }
1835
1836 const LevelInfoGL &TextureGL::getLevelInfo(gl::TextureTarget target, size_t level) const
1837 {
1838     return mLevelInfo[GetLevelInfoIndex(target, level)];
1839 }
1840
1841 const LevelInfoGL &TextureGL::getBaseLevelInfo() const
1842 {
1843     GLint effectiveBaseLevel = mState.getEffectiveBaseLevel();
1844     gl::TextureTarget target = getType() == gl::TextureType::CubeMap
1845                                    ? gl::kCubeMapTextureTargetMin
1846                                    : gl::NonCubeTextureTypeToTarget(getType());
1847     return getLevelInfo(target, effectiveBaseLevel);
1848 }
1849
1850 gl::TextureType TextureGL::getType() const
1851 {
1852     return mState.mType;
1853 }
1854
1855 angle::Result TextureGL::initializeContents(const gl::Context *context,
1856                                             const gl::ImageIndex &imageIndex)
1857 {
1858     ContextGL *contextGL              = GetImplAs<ContextGL>(context);
1859     const FunctionsGL *functions      = GetFunctionsGL(context);
1860     StateManagerGL *stateManager      = GetStateManagerGL(context);
1861     const angle::FeaturesGL &features = GetFeaturesGL(context);
1862
1863     bool shouldUseClear = !nativegl::SupportsTexImage(getType());
1864     GLenum nativeInternalFormat =
1865         getLevelInfo(imageIndex.getTarget(), imageIndex.getLevelIndex()).nativeInternalFormat;
1866     if ((features.allowClearForRobustResourceInit.enabled || shouldUseClear) &&
1867         nativegl::SupportsNativeRendering(functions, mState.getType(), nativeInternalFormat))
1868     {
1869         BlitGL *blitter = GetBlitGL(context);
1870
1871         int levelDepth = mState.getImageDesc(imageIndex).size.depth;
1872
1873         bool clearSucceeded = false;
1874         ANGLE_TRY(blitter->clearRenderableTexture(context, this, nativeInternalFormat, levelDepth,
1875                                                   imageIndex, &clearSucceeded));
1876         if (clearSucceeded)
1877         {
1878             return angle::Result::Continue;
1879         }
1880     }
1881
1882     // Either the texture is not renderable or was incomplete when clearing, fall back to a data
1883     // upload
1884     ASSERT(nativegl::SupportsTexImage(getType()));
1885     const gl::ImageDesc &desc                    = mState.getImageDesc(imageIndex);
1886     const gl::InternalFormat &internalFormatInfo = *desc.format.info;
1887
1888     gl::PixelUnpackState unpackState;
1889     unpackState.alignment = 1;
1890     stateManager->setPixelUnpackState(unpackState);
1891
1892     GLuint prevUnpackBuffer = stateManager->getBufferID(gl::BufferBinding::PixelUnpack);
1893     stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, 0);
1894
1895     stateManager->bindTexture(getType(), mTextureID);
1896     if (internalFormatInfo.compressed)
1897     {
1898         nativegl::CompressedTexSubImageFormat nativeSubImageFormat =
1899             nativegl::GetCompressedSubTexImageFormat(functions, features,
1900                                                      internalFormatInfo.internalFormat);
1901
1902         GLuint imageSize = 0;
1903         ANGLE_CHECK_GL_MATH(contextGL,
1904                             internalFormatInfo.computeCompressedImageSize(desc.size, &imageSize));
1905
1906         angle::MemoryBuffer *zero;
1907         ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
1908
1909         // WebGL spec requires that zero data is uploaded to compressed textures even if it might
1910         // not result in zero color data.
1911         if (nativegl::UseTexImage2D(getType()))
1912         {
1913             ANGLE_GL_TRY(context, functions->compressedTexSubImage2D(
1914                                       ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
1915                                       0, 0, desc.size.width, desc.size.height,
1916                                       nativeSubImageFormat.format, imageSize, zero->data()));
1917         }
1918         else
1919         {
1920             ASSERT(nativegl::UseTexImage3D(getType()));
1921             ANGLE_GL_TRY(context, functions->compressedTexSubImage3D(
1922                                       ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(),
1923                                       0, 0, 0, desc.size.width, desc.size.height, desc.size.depth,
1924                                       nativeSubImageFormat.format, imageSize, zero->data()));
1925         }
1926     }
1927     else
1928     {
1929         nativegl::TexSubImageFormat nativeSubImageFormat = nativegl::GetTexSubImageFormat(
1930             functions, features, internalFormatInfo.format, internalFormatInfo.type);
1931
1932         GLuint imageSize = 0;
1933         ANGLE_CHECK_GL_MATH(contextGL, internalFormatInfo.computePackUnpackEndByte(
1934                                            nativeSubImageFormat.type, desc.size, unpackState,
1935                                            nativegl::UseTexImage3D(getType()), &imageSize));
1936
1937         angle::MemoryBuffer *zero;
1938         ANGLE_CHECK_GL_ALLOC(contextGL, context->getZeroFilledBuffer(imageSize, &zero));
1939
1940         if (nativegl::UseTexImage2D(getType()))
1941         {
1942             ANGLE_GL_TRY(context,
1943                          functions->texSubImage2D(ToGLenum(imageIndex.getTarget()),
1944                                                   imageIndex.getLevelIndex(), 0, 0, desc.size.width,
1945                                                   desc.size.height, nativeSubImageFormat.format,
1946                                                   nativeSubImageFormat.type, zero->data()));
1947         }
1948         else
1949         {
1950             ASSERT(nativegl::UseTexImage3D(getType()));
1951             ANGLE_GL_TRY(context,
1952                          functions->texSubImage3D(
1953                              ToGLenum(imageIndex.getTarget()), imageIndex.getLevelIndex(), 0, 0, 0,
1954                              desc.size.width, desc.size.height, desc.size.depth,
1955                              nativeSubImageFormat.format, nativeSubImageFormat.type, zero->data()));
1956         }
1957     }
1958
1959     // Reset the pixel unpack state.  Because this call is made after synchronizing dirty bits in a
1960     // glTexImage call, we need to make sure that the texture data to be uploaded later has the
1961     // expected unpack state.
1962     stateManager->setPixelUnpackState(context->getState().getUnpackState());
1963     stateManager->bindBuffer(gl::BufferBinding::PixelUnpack, prevUnpackBuffer);
1964
1965     return angle::Result::Continue;
1966 }
1967
1968 }  // namespace rx