• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 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 // Texture.cpp: Implements the gl::Texture class. [OpenGL ES 2.0.24] section 3.7 page 63.
8 
9 #include "libANGLE/Texture.h"
10 
11 #include "common/mathutil.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Config.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/Image.h"
16 #include "libANGLE/State.h"
17 #include "libANGLE/Surface.h"
18 #include "libANGLE/formatutils.h"
19 #include "libANGLE/renderer/GLImplFactory.h"
20 #include "libANGLE/renderer/TextureImpl.h"
21 
22 namespace gl
23 {
24 
25 namespace
26 {
27 constexpr angle::SubjectIndex kBufferSubjectIndex = 2;
28 static_assert(kBufferSubjectIndex != rx::kTextureImageImplObserverMessageIndex, "Index collision");
29 static_assert(kBufferSubjectIndex != rx::kTextureImageSiblingMessageIndex, "Index collision");
30 
IsPointSampled(const SamplerState & samplerState)31 bool IsPointSampled(const SamplerState &samplerState)
32 {
33     return (samplerState.getMagFilter() == GL_NEAREST &&
34             (samplerState.getMinFilter() == GL_NEAREST ||
35              samplerState.getMinFilter() == GL_NEAREST_MIPMAP_NEAREST));
36 }
37 
GetImageDescIndex(TextureTarget target,size_t level)38 size_t GetImageDescIndex(TextureTarget target, size_t level)
39 {
40     return IsCubeMapFaceTarget(target) ? (level * 6 + CubeMapTextureTargetToFaceIndex(target))
41                                        : level;
42 }
43 
DetermineInitState(const Context * context,Buffer * unpackBuffer,const uint8_t * pixels)44 InitState DetermineInitState(const Context *context, Buffer *unpackBuffer, const uint8_t *pixels)
45 {
46     // Can happen in tests.
47     if (!context || !context->isRobustResourceInitEnabled())
48     {
49         return InitState::Initialized;
50     }
51 
52     return (!pixels && !unpackBuffer) ? InitState::MayNeedInit : InitState::Initialized;
53 }
54 }  // namespace
55 
IsMipmapFiltered(GLenum minFilterMode)56 bool IsMipmapFiltered(GLenum minFilterMode)
57 {
58     switch (minFilterMode)
59     {
60         case GL_NEAREST:
61         case GL_LINEAR:
62             return false;
63         case GL_NEAREST_MIPMAP_NEAREST:
64         case GL_LINEAR_MIPMAP_NEAREST:
65         case GL_NEAREST_MIPMAP_LINEAR:
66         case GL_LINEAR_MIPMAP_LINEAR:
67             return true;
68         default:
69             UNREACHABLE();
70             return false;
71     }
72 }
73 
ConvertToNearestFilterMode(GLenum filterMode)74 GLenum ConvertToNearestFilterMode(GLenum filterMode)
75 {
76     switch (filterMode)
77     {
78         case GL_LINEAR:
79             return GL_NEAREST;
80         case GL_LINEAR_MIPMAP_NEAREST:
81             return GL_NEAREST_MIPMAP_NEAREST;
82         case GL_LINEAR_MIPMAP_LINEAR:
83             return GL_NEAREST_MIPMAP_LINEAR;
84         default:
85             return filterMode;
86     }
87 }
88 
ConvertToNearestMipFilterMode(GLenum filterMode)89 GLenum ConvertToNearestMipFilterMode(GLenum filterMode)
90 {
91     switch (filterMode)
92     {
93         case GL_LINEAR_MIPMAP_LINEAR:
94             return GL_LINEAR_MIPMAP_NEAREST;
95         case GL_NEAREST_MIPMAP_LINEAR:
96             return GL_NEAREST_MIPMAP_NEAREST;
97         default:
98             return filterMode;
99     }
100 }
101 
IsMipmapSupported(const TextureType & type)102 bool IsMipmapSupported(const TextureType &type)
103 {
104     if (type == TextureType::_2DMultisample || type == TextureType::Buffer)
105     {
106         return false;
107     }
108     return true;
109 }
110 
SwizzleState()111 SwizzleState::SwizzleState()
112     : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
113 {}
114 
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)115 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
116     : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
117 {}
118 
swizzleRequired() const119 bool SwizzleState::swizzleRequired() const
120 {
121     return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
122            swizzleAlpha != GL_ALPHA;
123 }
124 
operator ==(const SwizzleState & other) const125 bool SwizzleState::operator==(const SwizzleState &other) const
126 {
127     return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
128            swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
129 }
130 
operator !=(const SwizzleState & other) const131 bool SwizzleState::operator!=(const SwizzleState &other) const
132 {
133     return !(*this == other);
134 }
135 
TextureState(TextureType type)136 TextureState::TextureState(TextureType type)
137     : mType(type),
138       mSamplerState(SamplerState::CreateDefaultForTarget(type)),
139       mSrgbOverride(SrgbOverride::Default),
140       mBaseLevel(0),
141       mMaxLevel(kInitialMaxLevel),
142       mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
143       mHasBeenBoundAsImage(false),
144       mHasBeenBoundAsAttachment(false),
145       mImmutableFormat(false),
146       mImmutableLevels(0),
147       mUsage(GL_NONE),
148       mHasProtectedContent(false),
149       mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
150       mCropRect(0, 0, 0, 0),
151       mGenerateMipmapHint(GL_FALSE),
152       mInitState(InitState::Initialized),
153       mCachedSamplerFormat(SamplerFormat::InvalidEnum),
154       mCachedSamplerCompareMode(GL_NONE),
155       mCachedSamplerFormatValid(false)
156 {}
157 
~TextureState()158 TextureState::~TextureState() {}
159 
swizzleRequired() const160 bool TextureState::swizzleRequired() const
161 {
162     return mSwizzleState.swizzleRequired();
163 }
164 
getEffectiveBaseLevel() const165 GLuint TextureState::getEffectiveBaseLevel() const
166 {
167     if (mImmutableFormat)
168     {
169         // GLES 3.0.4 section 3.8.10
170         return std::min(mBaseLevel, mImmutableLevels - 1);
171     }
172     // Some classes use the effective base level to index arrays with level data. By clamping the
173     // effective base level to max levels these arrays need just one extra item to store properties
174     // that should be returned for all out-of-range base level values, instead of needing special
175     // handling for out-of-range base levels.
176     return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
177 }
178 
getEffectiveMaxLevel() const179 GLuint TextureState::getEffectiveMaxLevel() const
180 {
181     if (mImmutableFormat)
182     {
183         // GLES 3.0.4 section 3.8.10
184         GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
185         clampedMaxLevel        = std::min(clampedMaxLevel, mImmutableLevels - 1);
186         return clampedMaxLevel;
187     }
188     return mMaxLevel;
189 }
190 
getMipmapMaxLevel() const191 GLuint TextureState::getMipmapMaxLevel() const
192 {
193     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
194     GLuint expectedMipLevels       = 0;
195     if (mType == TextureType::_3D)
196     {
197         const int maxDim  = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
198                                     baseImageDesc.size.depth);
199         expectedMipLevels = static_cast<GLuint>(log2(maxDim));
200     }
201     else
202     {
203         expectedMipLevels = static_cast<GLuint>(
204             log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
205     }
206 
207     return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
208 }
209 
setBaseLevel(GLuint baseLevel)210 bool TextureState::setBaseLevel(GLuint baseLevel)
211 {
212     if (mBaseLevel != baseLevel)
213     {
214         mBaseLevel = baseLevel;
215         return true;
216     }
217     return false;
218 }
219 
setMaxLevel(GLuint maxLevel)220 bool TextureState::setMaxLevel(GLuint maxLevel)
221 {
222     if (mMaxLevel != maxLevel)
223     {
224         mMaxLevel = maxLevel;
225         return true;
226     }
227 
228     return false;
229 }
230 
231 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
232 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
233 // per-level checks begin at the base-level.
234 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const235 bool TextureState::isCubeComplete() const
236 {
237     ASSERT(mType == TextureType::CubeMap);
238 
239     angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
240     const ImageDesc &baseImageDesc          = getImageDesc(*face, getEffectiveBaseLevel());
241     if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
242     {
243         return false;
244     }
245 
246     ++face;
247 
248     for (; face != kAfterCubeMapTextureTargetMax; ++face)
249     {
250         const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
251         if (faceImageDesc.size.width != baseImageDesc.size.width ||
252             faceImageDesc.size.height != baseImageDesc.size.height ||
253             !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
254         {
255             return false;
256         }
257     }
258 
259     return true;
260 }
261 
getBaseLevelDesc() const262 const ImageDesc &TextureState::getBaseLevelDesc() const
263 {
264     ASSERT(mType != TextureType::CubeMap || isCubeComplete());
265     return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
266 }
267 
getLevelZeroDesc() const268 const ImageDesc &TextureState::getLevelZeroDesc() const
269 {
270     ASSERT(mType != TextureType::CubeMap || isCubeComplete());
271     return getImageDesc(getBaseImageTarget(), 0);
272 }
273 
setCrop(const Rectangle & rect)274 void TextureState::setCrop(const Rectangle &rect)
275 {
276     mCropRect = rect;
277 }
278 
getCrop() const279 const Rectangle &TextureState::getCrop() const
280 {
281     return mCropRect;
282 }
283 
setGenerateMipmapHint(GLenum hint)284 void TextureState::setGenerateMipmapHint(GLenum hint)
285 {
286     mGenerateMipmapHint = hint;
287 }
288 
getGenerateMipmapHint() const289 GLenum TextureState::getGenerateMipmapHint() const
290 {
291     return mGenerateMipmapHint;
292 }
293 
computeRequiredSamplerFormat(const SamplerState & samplerState) const294 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
295 {
296     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
297     if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT ||
298          baseImageDesc.format.info->format == GL_DEPTH_STENCIL) &&
299         samplerState.getCompareMode() != GL_NONE)
300     {
301         return SamplerFormat::Shadow;
302     }
303     else
304     {
305         switch (baseImageDesc.format.info->componentType)
306         {
307             case GL_UNSIGNED_NORMALIZED:
308             case GL_SIGNED_NORMALIZED:
309             case GL_FLOAT:
310                 return SamplerFormat::Float;
311             case GL_INT:
312                 return SamplerFormat::Signed;
313             case GL_UNSIGNED_INT:
314                 return SamplerFormat::Unsigned;
315             default:
316                 return SamplerFormat::InvalidEnum;
317         }
318     }
319 }
320 
computeSamplerCompleteness(const SamplerState & samplerState,const State & state) const321 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
322                                               const State &state) const
323 {
324     // Buffer textures cannot be incomplete.
325     if (mType == TextureType::Buffer)
326     {
327         return true;
328     }
329 
330     if (!mImmutableFormat && mBaseLevel > mMaxLevel)
331     {
332         return false;
333     }
334     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
335     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
336         baseImageDesc.size.depth == 0)
337     {
338         return false;
339     }
340     // The cases where the texture is incomplete because base level is out of range should be
341     // handled by the above condition.
342     ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
343 
344     if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
345     {
346         return false;
347     }
348 
349     // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
350     // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
351     // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
352     // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
353     // incomplete texture. So, we ignore filtering for multisample texture completeness here.
354     if (!IsMultisampled(mType) &&
355         !baseImageDesc.format.info->filterSupport(state.getClientVersion(),
356                                                   state.getExtensions()) &&
357         !IsPointSampled(samplerState))
358     {
359         return false;
360     }
361     bool npotSupport = state.getExtensions().textureNpotOES || state.getClientMajorVersion() >= 3;
362     if (!npotSupport)
363     {
364         if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
365              samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
366             (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
367              samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
368         {
369             return false;
370         }
371     }
372 
373     if (IsMipmapSupported(mType) && IsMipmapFiltered(samplerState.getMinFilter()))
374     {
375         if (!npotSupport)
376         {
377             if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
378             {
379                 return false;
380             }
381         }
382 
383         if (!computeMipmapCompleteness())
384         {
385             return false;
386         }
387     }
388     else
389     {
390         if (mType == TextureType::CubeMap && !isCubeComplete())
391         {
392             return false;
393         }
394     }
395 
396     // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
397     // texture unit that would have been rejected by a call to TexParameter* for the texture bound
398     // to that unit, the behavior of the implementation is as if the texture were incomplete. For
399     // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
400     // sampler object bound to a texture unit and the texture bound to that unit is an external
401     // texture and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered
402     // incomplete.
403     // Sampler object state which does not affect sampling for the type of texture bound
404     // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect
405     // completeness.
406     if (mType == TextureType::External)
407     {
408         if (!state.getExtensions().EGLImageExternalWrapModesEXT)
409         {
410             if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
411                 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
412             {
413                 return false;
414             }
415         }
416 
417         if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
418         {
419             return false;
420         }
421     }
422 
423     // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
424     // The internalformat specified for the texture arrays is a sized internal depth or
425     // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
426     // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
427     // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
428     if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
429         state.getClientMajorVersion() >= 3)
430     {
431         // Note: we restrict this validation to sized types. For the OES_depth_textures
432         // extension, due to some underspecification problems, we must allow linear filtering
433         // for legacy compatibility with WebGL 1.
434         // See http://crbug.com/649200
435         if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
436         {
437             if ((samplerState.getMinFilter() != GL_NEAREST &&
438                  samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
439                 samplerState.getMagFilter() != GL_NEAREST)
440             {
441                 return false;
442             }
443         }
444     }
445 
446     // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
447     // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
448     // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
449     // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
450     // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
451     // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
452     // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
453     // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
454     // texture completeness here.
455     if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
456         mDepthStencilTextureMode == GL_STENCIL_INDEX)
457     {
458         if ((samplerState.getMinFilter() != GL_NEAREST &&
459              samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
460             samplerState.getMagFilter() != GL_NEAREST)
461         {
462             return false;
463         }
464     }
465 
466     return true;
467 }
468 
computeMipmapCompleteness() const469 bool TextureState::computeMipmapCompleteness() const
470 {
471     const GLuint maxLevel = getMipmapMaxLevel();
472 
473     for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
474     {
475         if (mType == TextureType::CubeMap)
476         {
477             for (TextureTarget face : AllCubeFaceTextureTargets())
478             {
479                 if (!computeLevelCompleteness(face, level))
480                 {
481                     return false;
482                 }
483             }
484         }
485         else
486         {
487             if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
488             {
489                 return false;
490             }
491         }
492     }
493 
494     return true;
495 }
496 
computeLevelCompleteness(TextureTarget target,size_t level) const497 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
498 {
499     ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
500 
501     if (mImmutableFormat)
502     {
503         return true;
504     }
505 
506     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
507     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
508         baseImageDesc.size.depth == 0)
509     {
510         return false;
511     }
512 
513     const ImageDesc &levelImageDesc = getImageDesc(target, level);
514     if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
515         levelImageDesc.size.depth == 0)
516     {
517         return false;
518     }
519 
520     if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
521     {
522         return false;
523     }
524 
525     ASSERT(level >= getEffectiveBaseLevel());
526     const size_t relativeLevel = level - getEffectiveBaseLevel();
527     if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
528     {
529         return false;
530     }
531 
532     if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
533     {
534         return false;
535     }
536 
537     if (mType == TextureType::_3D)
538     {
539         if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
540         {
541             return false;
542         }
543     }
544     else if (IsArrayTextureType(mType))
545     {
546         if (levelImageDesc.size.depth != baseImageDesc.size.depth)
547         {
548             return false;
549         }
550     }
551 
552     return true;
553 }
554 
getBaseImageTarget() const555 TextureTarget TextureState::getBaseImageTarget() const
556 {
557     return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
558                                          : NonCubeTextureTypeToTarget(mType);
559 }
560 
getEnabledLevelCount() const561 GLuint TextureState::getEnabledLevelCount() const
562 {
563     GLuint levelCount      = 0;
564     const GLuint baseLevel = getEffectiveBaseLevel();
565     const GLuint maxLevel  = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel());
566 
567     // The mip chain will have either one or more sequential levels, or max levels,
568     // but not a sparse one.
569     Optional<Extents> expectedSize;
570     for (size_t enabledLevel = baseLevel; enabledLevel <= maxLevel; ++enabledLevel, ++levelCount)
571     {
572         // Note: for cube textures, we only check the first face.
573         TextureTarget target     = TextureTypeToTarget(mType, 0);
574         size_t descIndex         = GetImageDescIndex(target, enabledLevel);
575         const Extents &levelSize = mImageDescs[descIndex].size;
576 
577         if (levelSize.empty())
578         {
579             break;
580         }
581         if (expectedSize.valid())
582         {
583             Extents newSize = expectedSize.value();
584             newSize.width   = std::max(1, newSize.width >> 1);
585             newSize.height  = std::max(1, newSize.height >> 1);
586 
587             if (!IsArrayTextureType(mType))
588             {
589                 newSize.depth = std::max(1, newSize.depth >> 1);
590             }
591 
592             if (newSize != levelSize)
593             {
594                 break;
595             }
596         }
597         expectedSize = levelSize;
598     }
599 
600     return levelCount;
601 }
602 
ImageDesc()603 ImageDesc::ImageDesc()
604     : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
605 {}
606 
ImageDesc(const Extents & size,const Format & format,const InitState initState)607 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
608     : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
609 {}
610 
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)611 ImageDesc::ImageDesc(const Extents &size,
612                      const Format &format,
613                      const GLsizei samples,
614                      const bool fixedSampleLocations,
615                      const InitState initState)
616     : size(size),
617       format(format),
618       samples(samples),
619       fixedSampleLocations(fixedSampleLocations),
620       initState(initState)
621 {}
622 
getMemorySize() const623 GLint ImageDesc::getMemorySize() const
624 {
625     // Assume allocated size is around width * height * depth * samples * pixelBytes
626     angle::CheckedNumeric<GLint> levelSize = 1;
627     levelSize *= format.info->pixelBytes;
628     levelSize *= size.width;
629     levelSize *= size.height;
630     levelSize *= size.depth;
631     levelSize *= std::max(samples, 1);
632     return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
633 }
634 
getImageDesc(TextureTarget target,size_t level) const635 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
636 {
637     size_t descIndex = GetImageDescIndex(target, level);
638     ASSERT(descIndex < mImageDescs.size());
639     return mImageDescs[descIndex];
640 }
641 
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)642 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
643 {
644     size_t descIndex = GetImageDescIndex(target, level);
645     ASSERT(descIndex < mImageDescs.size());
646     mImageDescs[descIndex] = desc;
647     if (desc.initState == InitState::MayNeedInit)
648     {
649         mInitState = InitState::MayNeedInit;
650     }
651     else
652     {
653         // Scan for any uninitialized images. If there are none, set the init state of the entire
654         // texture to initialized. The cost of the scan is only paid after doing image
655         // initialization which is already very expensive.
656         bool allImagesInitialized = true;
657 
658         for (const ImageDesc &initDesc : mImageDescs)
659         {
660             if (initDesc.initState == InitState::MayNeedInit)
661             {
662                 allImagesInitialized = false;
663                 break;
664             }
665         }
666 
667         if (allImagesInitialized)
668         {
669             mInitState = InitState::Initialized;
670         }
671     }
672 }
673 
674 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
675 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
676 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const677 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
678 {
679     if (imageIndex.isEntireLevelCubeMap())
680     {
681         ASSERT(isCubeComplete());
682         const GLint levelIndex = imageIndex.getLevelIndex();
683         return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
684     }
685 
686     return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
687 }
688 
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)689 void TextureState::setImageDescChain(GLuint baseLevel,
690                                      GLuint maxLevel,
691                                      Extents baseSize,
692                                      const Format &format,
693                                      InitState initState)
694 {
695     for (GLuint level = baseLevel; level <= maxLevel; level++)
696     {
697         int relativeLevel = (level - baseLevel);
698         Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
699                           std::max<int>(baseSize.height >> relativeLevel, 1),
700                           (IsArrayTextureType(mType))
701                               ? baseSize.depth
702                               : std::max<int>(baseSize.depth >> relativeLevel, 1));
703         ImageDesc levelInfo(levelSize, format, initState);
704 
705         if (mType == TextureType::CubeMap)
706         {
707             for (TextureTarget face : AllCubeFaceTextureTargets())
708             {
709                 setImageDesc(face, level, levelInfo);
710             }
711         }
712         else
713         {
714             setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
715         }
716     }
717 }
718 
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)719 void TextureState::setImageDescChainMultisample(Extents baseSize,
720                                                 const Format &format,
721                                                 GLsizei samples,
722                                                 bool fixedSampleLocations,
723                                                 InitState initState)
724 {
725     ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
726     ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
727     setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
728 }
729 
clearImageDesc(TextureTarget target,size_t level)730 void TextureState::clearImageDesc(TextureTarget target, size_t level)
731 {
732     setImageDesc(target, level, ImageDesc());
733 }
734 
clearImageDescs()735 void TextureState::clearImageDescs()
736 {
737     for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
738     {
739         mImageDescs[descIndex] = ImageDesc();
740     }
741 }
742 
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)743 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
744     : RefCountObject(factory->generateSerial(), id),
745       mState(type),
746       mTexture(factory->createTexture(mState)),
747       mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
748       mBufferObserver(this, kBufferSubjectIndex),
749       mBoundSurface(nullptr),
750       mBoundStream(nullptr)
751 {
752     mImplObserver.bind(mTexture);
753 
754     // Initially assume the implementation is dirty.
755     mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
756 }
757 
onDestroy(const Context * context)758 void Texture::onDestroy(const Context *context)
759 {
760     if (mBoundSurface)
761     {
762         ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
763         mBoundSurface = nullptr;
764     }
765     if (mBoundStream)
766     {
767         mBoundStream->releaseTextures();
768         mBoundStream = nullptr;
769     }
770 
771     egl::RefCountObjectReleaser<egl::Image> releaseImage;
772     (void)orphanImages(context, &releaseImage);
773 
774     mState.mBuffer.set(context, nullptr, 0, 0);
775 
776     if (mTexture)
777     {
778         mTexture->onDestroy(context);
779     }
780 }
781 
~Texture()782 Texture::~Texture()
783 {
784     SafeDelete(mTexture);
785 }
786 
setLabel(const Context * context,const std::string & label)787 void Texture::setLabel(const Context *context, const std::string &label)
788 {
789     mState.mLabel = label;
790 
791     if (mTexture)
792     {
793         mTexture->onLabelUpdate();
794     }
795 }
796 
getLabel() const797 const std::string &Texture::getLabel() const
798 {
799     return mState.mLabel;
800 }
801 
setSwizzleRed(const Context * context,GLenum swizzleRed)802 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
803 {
804     mState.mSwizzleState.swizzleRed = swizzleRed;
805     signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
806 }
807 
getSwizzleRed() const808 GLenum Texture::getSwizzleRed() const
809 {
810     return mState.mSwizzleState.swizzleRed;
811 }
812 
setSwizzleGreen(const Context * context,GLenum swizzleGreen)813 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
814 {
815     mState.mSwizzleState.swizzleGreen = swizzleGreen;
816     signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
817 }
818 
getSwizzleGreen() const819 GLenum Texture::getSwizzleGreen() const
820 {
821     return mState.mSwizzleState.swizzleGreen;
822 }
823 
setSwizzleBlue(const Context * context,GLenum swizzleBlue)824 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
825 {
826     mState.mSwizzleState.swizzleBlue = swizzleBlue;
827     signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
828 }
829 
getSwizzleBlue() const830 GLenum Texture::getSwizzleBlue() const
831 {
832     return mState.mSwizzleState.swizzleBlue;
833 }
834 
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)835 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
836 {
837     mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
838     signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
839 }
840 
getSwizzleAlpha() const841 GLenum Texture::getSwizzleAlpha() const
842 {
843     return mState.mSwizzleState.swizzleAlpha;
844 }
845 
setMinFilter(const Context * context,GLenum minFilter)846 void Texture::setMinFilter(const Context *context, GLenum minFilter)
847 {
848     if (mState.mSamplerState.setMinFilter(minFilter))
849     {
850         signalDirtyState(DIRTY_BIT_MIN_FILTER);
851     }
852 }
853 
getMinFilter() const854 GLenum Texture::getMinFilter() const
855 {
856     return mState.mSamplerState.getMinFilter();
857 }
858 
setMagFilter(const Context * context,GLenum magFilter)859 void Texture::setMagFilter(const Context *context, GLenum magFilter)
860 {
861     if (mState.mSamplerState.setMagFilter(magFilter))
862     {
863         signalDirtyState(DIRTY_BIT_MAG_FILTER);
864     }
865 }
866 
getMagFilter() const867 GLenum Texture::getMagFilter() const
868 {
869     return mState.mSamplerState.getMagFilter();
870 }
871 
setWrapS(const Context * context,GLenum wrapS)872 void Texture::setWrapS(const Context *context, GLenum wrapS)
873 {
874     if (mState.mSamplerState.setWrapS(wrapS))
875     {
876         signalDirtyState(DIRTY_BIT_WRAP_S);
877     }
878 }
879 
getWrapS() const880 GLenum Texture::getWrapS() const
881 {
882     return mState.mSamplerState.getWrapS();
883 }
884 
setWrapT(const Context * context,GLenum wrapT)885 void Texture::setWrapT(const Context *context, GLenum wrapT)
886 {
887     if (mState.mSamplerState.getWrapT() == wrapT)
888         return;
889     if (mState.mSamplerState.setWrapT(wrapT))
890     {
891         signalDirtyState(DIRTY_BIT_WRAP_T);
892     }
893 }
894 
getWrapT() const895 GLenum Texture::getWrapT() const
896 {
897     return mState.mSamplerState.getWrapT();
898 }
899 
setWrapR(const Context * context,GLenum wrapR)900 void Texture::setWrapR(const Context *context, GLenum wrapR)
901 {
902     if (mState.mSamplerState.setWrapR(wrapR))
903     {
904         signalDirtyState(DIRTY_BIT_WRAP_R);
905     }
906 }
907 
getWrapR() const908 GLenum Texture::getWrapR() const
909 {
910     return mState.mSamplerState.getWrapR();
911 }
912 
setMaxAnisotropy(const Context * context,float maxAnisotropy)913 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
914 {
915     if (mState.mSamplerState.setMaxAnisotropy(maxAnisotropy))
916     {
917         signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
918     }
919 }
920 
getMaxAnisotropy() const921 float Texture::getMaxAnisotropy() const
922 {
923     return mState.mSamplerState.getMaxAnisotropy();
924 }
925 
setMinLod(const Context * context,GLfloat minLod)926 void Texture::setMinLod(const Context *context, GLfloat minLod)
927 {
928     if (mState.mSamplerState.setMinLod(minLod))
929     {
930         signalDirtyState(DIRTY_BIT_MIN_LOD);
931     }
932 }
933 
getMinLod() const934 GLfloat Texture::getMinLod() const
935 {
936     return mState.mSamplerState.getMinLod();
937 }
938 
setMaxLod(const Context * context,GLfloat maxLod)939 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
940 {
941     if (mState.mSamplerState.setMaxLod(maxLod))
942     {
943         signalDirtyState(DIRTY_BIT_MAX_LOD);
944     }
945 }
946 
getMaxLod() const947 GLfloat Texture::getMaxLod() const
948 {
949     return mState.mSamplerState.getMaxLod();
950 }
951 
setCompareMode(const Context * context,GLenum compareMode)952 void Texture::setCompareMode(const Context *context, GLenum compareMode)
953 {
954     if (mState.mSamplerState.setCompareMode(compareMode))
955     {
956         signalDirtyState(DIRTY_BIT_COMPARE_MODE);
957     }
958 }
959 
getCompareMode() const960 GLenum Texture::getCompareMode() const
961 {
962     return mState.mSamplerState.getCompareMode();
963 }
964 
setCompareFunc(const Context * context,GLenum compareFunc)965 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
966 {
967     if (mState.mSamplerState.setCompareFunc(compareFunc))
968     {
969         signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
970     }
971 }
972 
getCompareFunc() const973 GLenum Texture::getCompareFunc() const
974 {
975     return mState.mSamplerState.getCompareFunc();
976 }
977 
setSRGBDecode(const Context * context,GLenum sRGBDecode)978 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
979 {
980     if (mState.mSamplerState.setSRGBDecode(sRGBDecode))
981     {
982         signalDirtyState(DIRTY_BIT_SRGB_DECODE);
983     }
984 }
985 
getSRGBDecode() const986 GLenum Texture::getSRGBDecode() const
987 {
988     return mState.mSamplerState.getSRGBDecode();
989 }
990 
setSRGBOverride(const Context * context,GLenum sRGBOverride)991 void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
992 {
993     SrgbOverride oldOverride = mState.mSrgbOverride;
994     mState.mSrgbOverride = (sRGBOverride == GL_SRGB) ? SrgbOverride::SRGB : SrgbOverride::Default;
995     if (mState.mSrgbOverride != oldOverride)
996     {
997         signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
998     }
999 }
1000 
getSRGBOverride() const1001 GLenum Texture::getSRGBOverride() const
1002 {
1003     return (mState.mSrgbOverride == SrgbOverride::SRGB) ? GL_SRGB : GL_NONE;
1004 }
1005 
getSamplerState() const1006 const SamplerState &Texture::getSamplerState() const
1007 {
1008     return mState.mSamplerState;
1009 }
1010 
setBaseLevel(const Context * context,GLuint baseLevel)1011 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
1012 {
1013     if (mState.setBaseLevel(baseLevel))
1014     {
1015         ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
1016         signalDirtyState(DIRTY_BIT_BASE_LEVEL);
1017     }
1018 
1019     return angle::Result::Continue;
1020 }
1021 
getBaseLevel() const1022 GLuint Texture::getBaseLevel() const
1023 {
1024     return mState.mBaseLevel;
1025 }
1026 
setMaxLevel(const Context * context,GLuint maxLevel)1027 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
1028 {
1029     if (mState.setMaxLevel(maxLevel))
1030     {
1031         signalDirtyState(DIRTY_BIT_MAX_LEVEL);
1032     }
1033 }
1034 
getMaxLevel() const1035 GLuint Texture::getMaxLevel() const
1036 {
1037     return mState.mMaxLevel;
1038 }
1039 
setDepthStencilTextureMode(const Context * context,GLenum mode)1040 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
1041 {
1042     if (mState.mDepthStencilTextureMode != mode)
1043     {
1044         mState.mDepthStencilTextureMode = mode;
1045         signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
1046     }
1047 }
1048 
getDepthStencilTextureMode() const1049 GLenum Texture::getDepthStencilTextureMode() const
1050 {
1051     return mState.mDepthStencilTextureMode;
1052 }
1053 
getImmutableFormat() const1054 bool Texture::getImmutableFormat() const
1055 {
1056     return mState.mImmutableFormat;
1057 }
1058 
getImmutableLevels() const1059 GLuint Texture::getImmutableLevels() const
1060 {
1061     return mState.mImmutableLevels;
1062 }
1063 
setUsage(const Context * context,GLenum usage)1064 void Texture::setUsage(const Context *context, GLenum usage)
1065 {
1066     mState.mUsage = usage;
1067     signalDirtyState(DIRTY_BIT_USAGE);
1068 }
1069 
getUsage() const1070 GLenum Texture::getUsage() const
1071 {
1072     return mState.mUsage;
1073 }
1074 
setProtectedContent(Context * context,bool hasProtectedContent)1075 void Texture::setProtectedContent(Context *context, bool hasProtectedContent)
1076 {
1077     mState.mHasProtectedContent = hasProtectedContent;
1078 }
1079 
hasProtectedContent() const1080 bool Texture::hasProtectedContent() const
1081 {
1082     return mState.mHasProtectedContent;
1083 }
1084 
getTextureState() const1085 const TextureState &Texture::getTextureState() const
1086 {
1087     return mState;
1088 }
1089 
getExtents(TextureTarget target,size_t level) const1090 const Extents &Texture::getExtents(TextureTarget target, size_t level) const
1091 {
1092     ASSERT(TextureTargetToType(target) == mState.mType);
1093     return mState.getImageDesc(target, level).size;
1094 }
1095 
getWidth(TextureTarget target,size_t level) const1096 size_t Texture::getWidth(TextureTarget target, size_t level) const
1097 {
1098     ASSERT(TextureTargetToType(target) == mState.mType);
1099     return mState.getImageDesc(target, level).size.width;
1100 }
1101 
getHeight(TextureTarget target,size_t level) const1102 size_t Texture::getHeight(TextureTarget target, size_t level) const
1103 {
1104     ASSERT(TextureTargetToType(target) == mState.mType);
1105     return mState.getImageDesc(target, level).size.height;
1106 }
1107 
getDepth(TextureTarget target,size_t level) const1108 size_t Texture::getDepth(TextureTarget target, size_t level) const
1109 {
1110     ASSERT(TextureTargetToType(target) == mState.mType);
1111     return mState.getImageDesc(target, level).size.depth;
1112 }
1113 
getFormat(TextureTarget target,size_t level) const1114 const Format &Texture::getFormat(TextureTarget target, size_t level) const
1115 {
1116     ASSERT(TextureTargetToType(target) == mState.mType);
1117     return mState.getImageDesc(target, level).format;
1118 }
1119 
getSamples(TextureTarget target,size_t level) const1120 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
1121 {
1122     ASSERT(TextureTargetToType(target) == mState.mType);
1123     return mState.getImageDesc(target, level).samples;
1124 }
1125 
getFixedSampleLocations(TextureTarget target,size_t level) const1126 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
1127 {
1128     ASSERT(TextureTargetToType(target) == mState.mType);
1129     return mState.getImageDesc(target, level).fixedSampleLocations;
1130 }
1131 
getMipmapMaxLevel() const1132 GLuint Texture::getMipmapMaxLevel() const
1133 {
1134     return mState.getMipmapMaxLevel();
1135 }
1136 
isMipmapComplete() const1137 bool Texture::isMipmapComplete() const
1138 {
1139     return mState.computeMipmapCompleteness();
1140 }
1141 
getBoundSurface() const1142 egl::Surface *Texture::getBoundSurface() const
1143 {
1144     return mBoundSurface;
1145 }
1146 
getBoundStream() const1147 egl::Stream *Texture::getBoundStream() const
1148 {
1149     return mBoundStream;
1150 }
1151 
getMemorySize() const1152 GLint Texture::getMemorySize() const
1153 {
1154     GLint implSize = mTexture->getMemorySize();
1155     if (implSize > 0)
1156     {
1157         return implSize;
1158     }
1159 
1160     angle::CheckedNumeric<GLint> size = 0;
1161     for (const ImageDesc &imageDesc : mState.mImageDescs)
1162     {
1163         size += imageDesc.getMemorySize();
1164     }
1165     return size.ValueOrDefault(std::numeric_limits<GLint>::max());
1166 }
1167 
getLevelMemorySize(TextureTarget target,GLint level) const1168 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
1169 {
1170     GLint implSize = mTexture->getLevelMemorySize(target, level);
1171     if (implSize > 0)
1172     {
1173         return implSize;
1174     }
1175 
1176     return mState.getImageDesc(target, level).getMemorySize();
1177 }
1178 
signalDirtyStorage(InitState initState)1179 void Texture::signalDirtyStorage(InitState initState)
1180 {
1181     mState.mInitState = initState;
1182     invalidateCompletenessCache();
1183     mState.mCachedSamplerFormatValid = false;
1184     onStateChange(angle::SubjectMessage::SubjectChanged);
1185 }
1186 
signalDirtyState(size_t dirtyBit)1187 void Texture::signalDirtyState(size_t dirtyBit)
1188 {
1189     mDirtyBits.set(dirtyBit);
1190     invalidateCompletenessCache();
1191     mState.mCachedSamplerFormatValid = false;
1192 
1193     if (dirtyBit == DIRTY_BIT_BASE_LEVEL || dirtyBit == DIRTY_BIT_MAX_LEVEL)
1194     {
1195         onStateChange(angle::SubjectMessage::SubjectChanged);
1196     }
1197     else
1198     {
1199         onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1200     }
1201 }
1202 
setImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type,const uint8_t * pixels)1203 angle::Result Texture::setImage(Context *context,
1204                                 const PixelUnpackState &unpackState,
1205                                 Buffer *unpackBuffer,
1206                                 TextureTarget target,
1207                                 GLint level,
1208                                 GLenum internalFormat,
1209                                 const Extents &size,
1210                                 GLenum format,
1211                                 GLenum type,
1212                                 const uint8_t *pixels)
1213 {
1214     ASSERT(TextureTargetToType(target) == mState.mType);
1215 
1216     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1217     ANGLE_TRY(releaseTexImageInternal(context));
1218 
1219     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1220     ANGLE_TRY(orphanImages(context, &releaseImage));
1221 
1222     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1223 
1224     ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1225                                  unpackBuffer, pixels));
1226 
1227     InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1228     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1229 
1230     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1231 
1232     signalDirtyStorage(initState);
1233 
1234     return angle::Result::Continue;
1235 }
1236 
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1237 angle::Result Texture::setSubImage(Context *context,
1238                                    const PixelUnpackState &unpackState,
1239                                    Buffer *unpackBuffer,
1240                                    TextureTarget target,
1241                                    GLint level,
1242                                    const Box &area,
1243                                    GLenum format,
1244                                    GLenum type,
1245                                    const uint8_t *pixels)
1246 {
1247     ASSERT(TextureTargetToType(target) == mState.mType);
1248 
1249     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1250     ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1251 
1252     ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1253                                     pixels));
1254 
1255     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1256 
1257     onStateChange(angle::SubjectMessage::ContentsChanged);
1258 
1259     return angle::Result::Continue;
1260 }
1261 
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1262 angle::Result Texture::setCompressedImage(Context *context,
1263                                           const PixelUnpackState &unpackState,
1264                                           TextureTarget target,
1265                                           GLint level,
1266                                           GLenum internalFormat,
1267                                           const Extents &size,
1268                                           size_t imageSize,
1269                                           const uint8_t *pixels)
1270 {
1271     ASSERT(TextureTargetToType(target) == mState.mType);
1272 
1273     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1274     ANGLE_TRY(releaseTexImageInternal(context));
1275 
1276     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1277     ANGLE_TRY(orphanImages(context, &releaseImage));
1278 
1279     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1280 
1281     ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1282                                            imageSize, pixels));
1283 
1284     Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1285 
1286     InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1287     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1288     signalDirtyStorage(initState);
1289 
1290     return angle::Result::Continue;
1291 }
1292 
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1293 angle::Result Texture::setCompressedSubImage(const Context *context,
1294                                              const PixelUnpackState &unpackState,
1295                                              TextureTarget target,
1296                                              GLint level,
1297                                              const Box &area,
1298                                              GLenum format,
1299                                              size_t imageSize,
1300                                              const uint8_t *pixels)
1301 {
1302     ASSERT(TextureTargetToType(target) == mState.mType);
1303 
1304     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1305     ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1306 
1307     ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1308                                               pixels));
1309 
1310     onStateChange(angle::SubjectMessage::ContentsChanged);
1311 
1312     return angle::Result::Continue;
1313 }
1314 
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1315 angle::Result Texture::copyImage(Context *context,
1316                                  TextureTarget target,
1317                                  GLint level,
1318                                  const Rectangle &sourceArea,
1319                                  GLenum internalFormat,
1320                                  Framebuffer *source)
1321 {
1322     ASSERT(TextureTargetToType(target) == mState.mType);
1323 
1324     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1325     ANGLE_TRY(releaseTexImageInternal(context));
1326 
1327     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1328     ANGLE_TRY(orphanImages(context, &releaseImage));
1329 
1330     ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1331 
1332     const InternalFormat &internalFormatInfo =
1333         GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1334 
1335     // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1336     // other pixels untouched. For safety in robust resource initialization, assume that that
1337     // clipping is going to occur when computing the region for which to ensure initialization. If
1338     // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1339     // going to be set during the copy operation.
1340     Box destBox;
1341     bool forceCopySubImage = false;
1342     if (context->isRobustResourceInitEnabled())
1343     {
1344         const FramebufferAttachment *sourceReadAttachment = source->getReadColorAttachment();
1345         Extents fbSize                                    = sourceReadAttachment->getSize();
1346         // Force using copySubImage when the source area is out of bounds AND
1347         // we're not copying to and from the same texture
1348         forceCopySubImage = ((sourceArea.x < 0) || (sourceArea.y < 0) ||
1349                              ((sourceArea.x + sourceArea.width) > fbSize.width) ||
1350                              ((sourceArea.y + sourceArea.height) > fbSize.height)) &&
1351                             (sourceReadAttachment->getResource() != this);
1352         Rectangle clippedArea;
1353         if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1354         {
1355             const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1356                                        0);
1357             destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1358                           clippedArea.height, 1);
1359         }
1360     }
1361 
1362     InitState initState = DetermineInitState(context, nullptr, nullptr);
1363 
1364     // If we need to initialize the destination texture we split the call into a create call,
1365     // an initializeContents call, and then a copySubImage call. This ensures the destination
1366     // texture exists before we try to clear it.
1367     Extents size(sourceArea.width, sourceArea.height, 1);
1368     if (forceCopySubImage || doesSubImageNeedInit(context, index, destBox))
1369     {
1370         ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1371                                      internalFormatInfo.format, internalFormatInfo.type,
1372                                      PixelUnpackState(), nullptr, nullptr));
1373         mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormatInfo), initState));
1374         ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1375         ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1376     }
1377     else
1378     {
1379         ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1380     }
1381 
1382     mState.setImageDesc(target, level,
1383                         ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1384 
1385     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1386 
1387     // Because this could affect the texture storage we might need to init other layers/levels.
1388     signalDirtyStorage(initState);
1389 
1390     return angle::Result::Continue;
1391 }
1392 
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1393 angle::Result Texture::copySubImage(Context *context,
1394                                     const ImageIndex &index,
1395                                     const Offset &destOffset,
1396                                     const Rectangle &sourceArea,
1397                                     Framebuffer *source)
1398 {
1399     ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1400 
1401     // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1402     // other pixels untouched. For safety in robust resource initialization, assume that that
1403     // clipping is going to occur when computing the region for which to ensure initialization. If
1404     // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1405     // going to be set during the copy operation. Note that this assumes that
1406     // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1407     // just a sub-region.
1408     Box destBox;
1409     if (context->isRobustResourceInitEnabled())
1410     {
1411         Extents fbSize = source->getReadColorAttachment()->getSize();
1412         Rectangle clippedArea;
1413         if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1414         {
1415             const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1416                                        destOffset.y + clippedArea.y - sourceArea.y, 0);
1417             destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1418                           clippedArea.height, 1);
1419         }
1420     }
1421 
1422     ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1423 
1424     ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1425     ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1426 
1427     onStateChange(angle::SubjectMessage::ContentsChanged);
1428 
1429     return angle::Result::Continue;
1430 }
1431 
copyRenderbufferSubData(Context * context,const gl::Renderbuffer * srcBuffer,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)1432 angle::Result Texture::copyRenderbufferSubData(Context *context,
1433                                                const gl::Renderbuffer *srcBuffer,
1434                                                GLint srcLevel,
1435                                                GLint srcX,
1436                                                GLint srcY,
1437                                                GLint srcZ,
1438                                                GLint dstLevel,
1439                                                GLint dstX,
1440                                                GLint dstY,
1441                                                GLint dstZ,
1442                                                GLsizei srcWidth,
1443                                                GLsizei srcHeight,
1444                                                GLsizei srcDepth)
1445 {
1446     ANGLE_TRY(mTexture->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY, srcZ,
1447                                                 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1448                                                 srcDepth));
1449 
1450     signalDirtyStorage(InitState::Initialized);
1451 
1452     return angle::Result::Continue;
1453 }
1454 
copyTextureSubData(Context * context,const gl::Texture * srcTexture,GLint srcLevel,GLint srcX,GLint srcY,GLint srcZ,GLint dstLevel,GLint dstX,GLint dstY,GLint dstZ,GLsizei srcWidth,GLsizei srcHeight,GLsizei srcDepth)1455 angle::Result Texture::copyTextureSubData(Context *context,
1456                                           const gl::Texture *srcTexture,
1457                                           GLint srcLevel,
1458                                           GLint srcX,
1459                                           GLint srcY,
1460                                           GLint srcZ,
1461                                           GLint dstLevel,
1462                                           GLint dstX,
1463                                           GLint dstY,
1464                                           GLint dstZ,
1465                                           GLsizei srcWidth,
1466                                           GLsizei srcHeight,
1467                                           GLsizei srcDepth)
1468 {
1469     ANGLE_TRY(mTexture->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
1470                                            dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1471                                            srcDepth));
1472 
1473     signalDirtyStorage(InitState::Initialized);
1474 
1475     return angle::Result::Continue;
1476 }
1477 
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1478 angle::Result Texture::copyTexture(Context *context,
1479                                    TextureTarget target,
1480                                    GLint level,
1481                                    GLenum internalFormat,
1482                                    GLenum type,
1483                                    GLint sourceLevel,
1484                                    bool unpackFlipY,
1485                                    bool unpackPremultiplyAlpha,
1486                                    bool unpackUnmultiplyAlpha,
1487                                    Texture *source)
1488 {
1489     ASSERT(TextureTargetToType(target) == mState.mType);
1490     ASSERT(source->getType() != TextureType::CubeMap);
1491 
1492     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1493     ANGLE_TRY(releaseTexImageInternal(context));
1494 
1495     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1496     ANGLE_TRY(orphanImages(context, &releaseImage));
1497 
1498     // Initialize source texture.
1499     // Note: we don't have a way to notify which portions of the image changed currently.
1500     ANGLE_TRY(source->ensureInitialized(context));
1501 
1502     ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1503 
1504     ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1505                                     unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1506 
1507     const auto &sourceDesc =
1508         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1509     const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1510     mState.setImageDesc(
1511         target, level,
1512         ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1513 
1514     signalDirtyStorage(InitState::Initialized);
1515 
1516     return angle::Result::Continue;
1517 }
1518 
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1519 angle::Result Texture::copySubTexture(const Context *context,
1520                                       TextureTarget target,
1521                                       GLint level,
1522                                       const Offset &destOffset,
1523                                       GLint sourceLevel,
1524                                       const Box &sourceBox,
1525                                       bool unpackFlipY,
1526                                       bool unpackPremultiplyAlpha,
1527                                       bool unpackUnmultiplyAlpha,
1528                                       Texture *source)
1529 {
1530     ASSERT(TextureTargetToType(target) == mState.mType);
1531 
1532     // Ensure source is initialized.
1533     ANGLE_TRY(source->ensureInitialized(context));
1534 
1535     Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1536                 sourceBox.depth);
1537     ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1538     ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1539 
1540     ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1541                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1542                                        source));
1543 
1544     onStateChange(angle::SubjectMessage::ContentsChanged);
1545 
1546     return angle::Result::Continue;
1547 }
1548 
copyCompressedTexture(Context * context,const Texture * source)1549 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1550 {
1551     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1552     ANGLE_TRY(releaseTexImageInternal(context));
1553 
1554     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1555     ANGLE_TRY(orphanImages(context, &releaseImage));
1556 
1557     ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1558 
1559     ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1560     const auto &sourceDesc =
1561         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1562     mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1563 
1564     return angle::Result::Continue;
1565 }
1566 
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1567 angle::Result Texture::setStorage(Context *context,
1568                                   TextureType type,
1569                                   GLsizei levels,
1570                                   GLenum internalFormat,
1571                                   const Extents &size)
1572 {
1573     ASSERT(type == mState.mType);
1574 
1575     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1576     ANGLE_TRY(releaseTexImageInternal(context));
1577 
1578     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1579     ANGLE_TRY(orphanImages(context, &releaseImage));
1580 
1581     mState.mImmutableFormat = true;
1582     mState.mImmutableLevels = static_cast<GLuint>(levels);
1583     mState.clearImageDescs();
1584     InitState initState = DetermineInitState(context, nullptr, nullptr);
1585     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1586                              initState);
1587 
1588     ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1589 
1590     // Changing the texture to immutable can trigger a change in the base and max levels:
1591     // GLES 3.0.4 section 3.8.10 pg 158:
1592     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1593     // clamped to the range[levelbase;levels].
1594     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1595     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1596 
1597     signalDirtyStorage(initState);
1598 
1599     return angle::Result::Continue;
1600 }
1601 
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1602 angle::Result Texture::setImageExternal(Context *context,
1603                                         TextureTarget target,
1604                                         GLint level,
1605                                         GLenum internalFormat,
1606                                         const Extents &size,
1607                                         GLenum format,
1608                                         GLenum type)
1609 {
1610     ASSERT(TextureTargetToType(target) == mState.mType);
1611 
1612     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1613     ANGLE_TRY(releaseTexImageInternal(context));
1614 
1615     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1616     ANGLE_TRY(orphanImages(context, &releaseImage));
1617 
1618     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1619 
1620     ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1621 
1622     InitState initState = InitState::Initialized;
1623     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1624 
1625     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1626 
1627     signalDirtyStorage(initState);
1628 
1629     return angle::Result::Continue;
1630 }
1631 
setStorageMultisample(Context * context,TextureType type,GLsizei samplesIn,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1632 angle::Result Texture::setStorageMultisample(Context *context,
1633                                              TextureType type,
1634                                              GLsizei samplesIn,
1635                                              GLint internalFormat,
1636                                              const Extents &size,
1637                                              bool fixedSampleLocations)
1638 {
1639     ASSERT(type == mState.mType);
1640 
1641     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1642     ANGLE_TRY(releaseTexImageInternal(context));
1643 
1644     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1645     ANGLE_TRY(orphanImages(context, &releaseImage));
1646 
1647     // Potentially adjust "samples" to a supported value
1648     const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1649     GLsizei samples               = formatCaps.getNearestSamples(samplesIn);
1650 
1651     mState.mImmutableFormat = true;
1652     mState.mImmutableLevels = static_cast<GLuint>(1);
1653     mState.clearImageDescs();
1654     InitState initState = DetermineInitState(context, nullptr, nullptr);
1655     mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1656                                         initState);
1657 
1658     ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1659                                               fixedSampleLocations));
1660     signalDirtyStorage(initState);
1661 
1662     return angle::Result::Continue;
1663 }
1664 
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)1665 angle::Result Texture::setStorageExternalMemory(Context *context,
1666                                                 TextureType type,
1667                                                 GLsizei levels,
1668                                                 GLenum internalFormat,
1669                                                 const Extents &size,
1670                                                 MemoryObject *memoryObject,
1671                                                 GLuint64 offset,
1672                                                 GLbitfield createFlags,
1673                                                 GLbitfield usageFlags,
1674                                                 const void *imageCreateInfoPNext)
1675 {
1676     ASSERT(type == mState.mType);
1677 
1678     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1679     ANGLE_TRY(releaseTexImageInternal(context));
1680 
1681     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1682     ANGLE_TRY(orphanImages(context, &releaseImage));
1683 
1684     ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1685                                                  memoryObject, offset, createFlags, usageFlags,
1686                                                  imageCreateInfoPNext));
1687 
1688     mState.mImmutableFormat = true;
1689     mState.mImmutableLevels = static_cast<GLuint>(levels);
1690     mState.clearImageDescs();
1691     InitState initState = DetermineInitState(context, nullptr, nullptr);
1692     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1693                              initState);
1694 
1695     // Changing the texture to immutable can trigger a change in the base and max levels:
1696     // GLES 3.0.4 section 3.8.10 pg 158:
1697     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1698     // clamped to the range[levelbase;levels].
1699     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1700     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1701 
1702     signalDirtyStorage(initState);
1703 
1704     return angle::Result::Continue;
1705 }
1706 
generateMipmap(Context * context)1707 angle::Result Texture::generateMipmap(Context *context)
1708 {
1709     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1710     ANGLE_TRY(releaseTexImageInternal(context));
1711 
1712     // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1713     // is not mip complete.
1714     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1715     if (!isMipmapComplete())
1716     {
1717         ANGLE_TRY(orphanImages(context, &releaseImage));
1718     }
1719 
1720     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1721     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1722 
1723     if (maxLevel <= baseLevel)
1724     {
1725         return angle::Result::Continue;
1726     }
1727 
1728     // If any dimension is zero, this is a no-op:
1729     //
1730     // > Otherwise, if level_base is not defined, or if any dimension is zero, all mipmap levels are
1731     // > left unchanged. This is not an error.
1732     const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1733     if (baseImageInfo.size.empty())
1734     {
1735         return angle::Result::Continue;
1736     }
1737 
1738     // Clear the base image(s) immediately if needed
1739     if (context->isRobustResourceInitEnabled())
1740     {
1741         ImageIndexIterator it =
1742             ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1743                                             ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1744         while (it.hasNext())
1745         {
1746             const ImageIndex index = it.next();
1747             const ImageDesc &desc  = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1748 
1749             if (desc.initState == InitState::MayNeedInit)
1750             {
1751                 ANGLE_TRY(initializeContents(context, index));
1752             }
1753         }
1754     }
1755 
1756     ANGLE_TRY(syncState(context, Command::GenerateMipmap));
1757     ANGLE_TRY(mTexture->generateMipmap(context));
1758 
1759     // Propagate the format and size of the base mip to the smaller ones. Cube maps are guaranteed
1760     // to have faces of the same size and format so any faces can be picked.
1761     mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1762                              InitState::Initialized);
1763 
1764     signalDirtyStorage(InitState::Initialized);
1765 
1766     return angle::Result::Continue;
1767 }
1768 
bindTexImageFromSurface(Context * context,egl::Surface * surface)1769 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1770 {
1771     ASSERT(surface);
1772 
1773     if (mBoundSurface)
1774     {
1775         ANGLE_TRY(releaseTexImageFromSurface(context));
1776     }
1777 
1778     ANGLE_TRY(mTexture->bindTexImage(context, surface));
1779     mBoundSurface = surface;
1780 
1781     // Set the image info to the size and format of the surface
1782     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1783     Extents size(surface->getWidth(), surface->getHeight(), 1);
1784     ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1785     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1786     mState.mHasProtectedContent = surface->hasProtectedContent();
1787     signalDirtyStorage(InitState::Initialized);
1788     return angle::Result::Continue;
1789 }
1790 
releaseTexImageFromSurface(const Context * context)1791 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1792 {
1793     ASSERT(mBoundSurface);
1794     mBoundSurface = nullptr;
1795     ANGLE_TRY(mTexture->releaseTexImage(context));
1796 
1797     // Erase the image info for level 0
1798     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1799     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1800     mState.mHasProtectedContent = false;
1801     signalDirtyStorage(InitState::Initialized);
1802     return angle::Result::Continue;
1803 }
1804 
bindStream(egl::Stream * stream)1805 void Texture::bindStream(egl::Stream *stream)
1806 {
1807     ASSERT(stream);
1808 
1809     // It should not be possible to bind a texture already bound to another stream
1810     ASSERT(mBoundStream == nullptr);
1811 
1812     mBoundStream = stream;
1813 
1814     ASSERT(mState.mType == TextureType::External);
1815 }
1816 
releaseStream()1817 void Texture::releaseStream()
1818 {
1819     ASSERT(mBoundStream);
1820     mBoundStream = nullptr;
1821 }
1822 
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1823 angle::Result Texture::acquireImageFromStream(const Context *context,
1824                                               const egl::Stream::GLTextureDescription &desc)
1825 {
1826     ASSERT(mBoundStream != nullptr);
1827     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1828 
1829     Extents size(desc.width, desc.height, 1);
1830     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1831                         ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1832     signalDirtyStorage(InitState::Initialized);
1833     return angle::Result::Continue;
1834 }
1835 
releaseImageFromStream(const Context * context)1836 angle::Result Texture::releaseImageFromStream(const Context *context)
1837 {
1838     ASSERT(mBoundStream != nullptr);
1839     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1840                                          egl::Stream::GLTextureDescription()));
1841 
1842     // Set to incomplete
1843     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1844     signalDirtyStorage(InitState::Initialized);
1845     return angle::Result::Continue;
1846 }
1847 
releaseTexImageInternal(Context * context)1848 angle::Result Texture::releaseTexImageInternal(Context *context)
1849 {
1850     if (mBoundSurface)
1851     {
1852         // Notify the surface
1853         egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1854         // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1855         if (eglErr.isError())
1856         {
1857             context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1858                                  __FILE__, ANGLE_FUNCTION, __LINE__);
1859         }
1860 
1861         // Then, call the same method as from the surface
1862         ANGLE_TRY(releaseTexImageFromSurface(context));
1863     }
1864     return angle::Result::Continue;
1865 }
1866 
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1867 angle::Result Texture::setEGLImageTarget(Context *context,
1868                                          TextureType type,
1869                                          egl::Image *imageTarget)
1870 {
1871     ASSERT(type == mState.mType);
1872     ASSERT(type == TextureType::_2D || type == TextureType::External ||
1873            type == TextureType::_2DArray);
1874 
1875     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1876     ANGLE_TRY(releaseTexImageInternal(context));
1877 
1878     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1879     ANGLE_TRY(orphanImages(context, &releaseImage));
1880 
1881     ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1882 
1883     setTargetImage(context, imageTarget);
1884 
1885     Extents size(static_cast<int>(imageTarget->getWidth()),
1886                  static_cast<int>(imageTarget->getHeight()), 1);
1887 
1888     auto initState = imageTarget->sourceInitState();
1889 
1890     mState.clearImageDescs();
1891     mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1892                         ImageDesc(size, imageTarget->getFormat(), initState));
1893     mState.mHasProtectedContent = imageTarget->hasProtectedContent();
1894     signalDirtyStorage(initState);
1895 
1896     return angle::Result::Continue;
1897 }
1898 
getAttachmentSize(const ImageIndex & imageIndex) const1899 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1900 {
1901     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1902     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1903     // one that belongs to the first face of the cube map.
1904     if (imageIndex.isEntireLevelCubeMap())
1905     {
1906         // A cube map texture is cube complete if the following conditions all hold true:
1907         // - The levelbase arrays of each of the six texture images making up the cube map have
1908         //   identical, positive, and square dimensions.
1909         if (!mState.isCubeComplete())
1910         {
1911             return Extents();
1912         }
1913     }
1914 
1915     return mState.getImageDesc(imageIndex).size;
1916 }
1917 
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1918 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1919 {
1920     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1921     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1922     // one that belongs to the first face of the cube map.
1923     if (imageIndex.isEntireLevelCubeMap())
1924     {
1925         // A cube map texture is cube complete if the following conditions all hold true:
1926         // - The levelbase arrays were each specified with the same effective internal format.
1927         if (!mState.isCubeComplete())
1928         {
1929             return Format::Invalid();
1930         }
1931     }
1932     return mState.getImageDesc(imageIndex).format;
1933 }
1934 
getAttachmentSamples(const ImageIndex & imageIndex) const1935 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1936 {
1937     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1938     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1939     if (imageIndex.isEntireLevelCubeMap())
1940     {
1941         return 0;
1942     }
1943 
1944     return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1945 }
1946 
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1947 bool Texture::isRenderable(const Context *context,
1948                            GLenum binding,
1949                            const ImageIndex &imageIndex) const
1950 {
1951     if (isEGLImageTarget())
1952     {
1953         return ImageSibling::isRenderable(context, binding, imageIndex);
1954     }
1955 
1956     // Surfaces bound to textures are always renderable. This avoids issues with surfaces with ES3+
1957     // formats not being renderable when bound to textures in ES2 contexts.
1958     if (mBoundSurface)
1959     {
1960         return true;
1961     }
1962 
1963     return getAttachmentFormat(binding, imageIndex)
1964         .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1965 }
1966 
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1967 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1968 {
1969     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1970     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1971     if (imageIndex.isEntireLevelCubeMap())
1972     {
1973         return true;
1974     }
1975 
1976     // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1977     // the same for all attached textures.
1978     return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1979 }
1980 
setBorderColor(const Context * context,const ColorGeneric & color)1981 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1982 {
1983     mState.mSamplerState.setBorderColor(color);
1984     signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1985 }
1986 
getBorderColor() const1987 const ColorGeneric &Texture::getBorderColor() const
1988 {
1989     return mState.mSamplerState.getBorderColor();
1990 }
1991 
getRequiredTextureImageUnits(const Context * context) const1992 GLint Texture::getRequiredTextureImageUnits(const Context *context) const
1993 {
1994     // Only external texture types can return non-1.
1995     if (mState.mType != TextureType::External)
1996     {
1997         return 1;
1998     }
1999 
2000     return mTexture->getRequiredExternalTextureImageUnits(context);
2001 }
2002 
setCrop(const Rectangle & rect)2003 void Texture::setCrop(const Rectangle &rect)
2004 {
2005     mState.setCrop(rect);
2006 }
2007 
getCrop() const2008 const Rectangle &Texture::getCrop() const
2009 {
2010     return mState.getCrop();
2011 }
2012 
setGenerateMipmapHint(GLenum hint)2013 void Texture::setGenerateMipmapHint(GLenum hint)
2014 {
2015     mState.setGenerateMipmapHint(hint);
2016 }
2017 
getGenerateMipmapHint() const2018 GLenum Texture::getGenerateMipmapHint() const
2019 {
2020     return mState.getGenerateMipmapHint();
2021 }
2022 
setBuffer(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat)2023 angle::Result Texture::setBuffer(const gl::Context *context,
2024                                  gl::Buffer *buffer,
2025                                  GLenum internalFormat)
2026 {
2027     // Use 0 to indicate that the size is taken from whatever size the buffer has when the texture
2028     // buffer is used.
2029     return setBufferRange(context, buffer, internalFormat, 0, 0);
2030 }
2031 
setBufferRange(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat,GLintptr offset,GLsizeiptr size)2032 angle::Result Texture::setBufferRange(const gl::Context *context,
2033                                       gl::Buffer *buffer,
2034                                       GLenum internalFormat,
2035                                       GLintptr offset,
2036                                       GLsizeiptr size)
2037 {
2038     mState.mImmutableFormat = true;
2039     mState.mBuffer.set(context, buffer, offset, size);
2040     ANGLE_TRY(mTexture->setBuffer(context, internalFormat));
2041 
2042     mState.clearImageDescs();
2043     if (buffer == nullptr)
2044     {
2045         mBufferObserver.reset();
2046         InitState initState = DetermineInitState(context, nullptr, nullptr);
2047         signalDirtyStorage(initState);
2048         return angle::Result::Continue;
2049     }
2050 
2051     size = GetBoundBufferAvailableSize(mState.mBuffer);
2052 
2053     mState.mImmutableLevels           = static_cast<GLuint>(1);
2054     InternalFormat internalFormatInfo = GetSizedInternalFormatInfo(internalFormat);
2055     Format format(internalFormat);
2056     Extents extents(static_cast<GLuint>(size / internalFormatInfo.pixelBytes), 1, 1);
2057     InitState initState = buffer->initState();
2058     mState.setImageDesc(TextureTarget::Buffer, 0, ImageDesc(extents, format, initState));
2059 
2060     signalDirtyStorage(initState);
2061 
2062     // Observe modifications to the buffer, so that extents can be updated.
2063     mBufferObserver.bind(buffer);
2064 
2065     return angle::Result::Continue;
2066 }
2067 
getBuffer() const2068 const OffsetBindingPointer<Buffer> &Texture::getBuffer() const
2069 {
2070     return mState.mBuffer;
2071 }
2072 
onAttach(const Context * context,rx::Serial framebufferSerial)2073 void Texture::onAttach(const Context *context, rx::Serial framebufferSerial)
2074 {
2075     addRef();
2076 
2077     // Duplicates allowed for multiple attachment points. See the comment in the header.
2078     mBoundFramebufferSerials.push_back(framebufferSerial);
2079 
2080     if (!mState.mHasBeenBoundAsAttachment)
2081     {
2082         mDirtyBits.set(DIRTY_BIT_BOUND_AS_ATTACHMENT);
2083         mState.mHasBeenBoundAsAttachment = true;
2084     }
2085 }
2086 
onDetach(const Context * context,rx::Serial framebufferSerial)2087 void Texture::onDetach(const Context *context, rx::Serial framebufferSerial)
2088 {
2089     // Erase first instance. If there are multiple bindings, leave the others.
2090     ASSERT(isBoundToFramebuffer(framebufferSerial));
2091     mBoundFramebufferSerials.remove_and_permute(framebufferSerial);
2092 
2093     release(context);
2094 }
2095 
getId() const2096 GLuint Texture::getId() const
2097 {
2098     return id().value;
2099 }
2100 
getNativeID() const2101 GLuint Texture::getNativeID() const
2102 {
2103     return mTexture->getNativeID();
2104 }
2105 
syncState(const Context * context,Command source)2106 angle::Result Texture::syncState(const Context *context, Command source)
2107 {
2108     ASSERT(hasAnyDirtyBit() || source == Command::GenerateMipmap);
2109     ANGLE_TRY(mTexture->syncState(context, mDirtyBits, source));
2110     mDirtyBits.reset();
2111     mState.mInitState = InitState::Initialized;
2112     return angle::Result::Continue;
2113 }
2114 
getAttachmentImpl() const2115 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
2116 {
2117     return mTexture;
2118 }
2119 
isSamplerComplete(const Context * context,const Sampler * optionalSampler)2120 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
2121 {
2122     const auto &samplerState =
2123         optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
2124     const auto &contextState = context->getState();
2125 
2126     if (contextState.getContextID() != mCompletenessCache.context ||
2127         !mCompletenessCache.samplerState.sameCompleteness(samplerState))
2128     {
2129         mCompletenessCache.context      = context->getState().getContextID();
2130         mCompletenessCache.samplerState = samplerState;
2131         mCompletenessCache.samplerComplete =
2132             mState.computeSamplerCompleteness(samplerState, contextState);
2133     }
2134 
2135     return mCompletenessCache.samplerComplete;
2136 }
2137 
SamplerCompletenessCache()2138 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
2139     : context({0}), samplerState(), samplerComplete(false)
2140 {}
2141 
invalidateCompletenessCache() const2142 void Texture::invalidateCompletenessCache() const
2143 {
2144     mCompletenessCache.context = {0};
2145 }
2146 
ensureInitialized(const Context * context)2147 angle::Result Texture::ensureInitialized(const Context *context)
2148 {
2149     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2150     {
2151         return angle::Result::Continue;
2152     }
2153 
2154     bool anyDirty = false;
2155 
2156     ImageIndexIterator it =
2157         ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
2158                                         ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
2159     while (it.hasNext())
2160     {
2161         const ImageIndex index = it.next();
2162         ImageDesc &desc =
2163             mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
2164         if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
2165         {
2166             ASSERT(mState.mInitState == InitState::MayNeedInit);
2167             ANGLE_TRY(initializeContents(context, index));
2168             desc.initState = InitState::Initialized;
2169             anyDirty       = true;
2170         }
2171     }
2172     if (anyDirty)
2173     {
2174         signalDirtyStorage(InitState::Initialized);
2175     }
2176     mState.mInitState = InitState::Initialized;
2177 
2178     return angle::Result::Continue;
2179 }
2180 
initState(const ImageIndex & imageIndex) const2181 InitState Texture::initState(const ImageIndex &imageIndex) const
2182 {
2183     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2184     // we need to check all the related ImageDescs.
2185     if (imageIndex.isEntireLevelCubeMap())
2186     {
2187         const GLint levelIndex = imageIndex.getLevelIndex();
2188         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2189         {
2190             if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
2191             {
2192                 return InitState::MayNeedInit;
2193             }
2194         }
2195         return InitState::Initialized;
2196     }
2197 
2198     return mState.getImageDesc(imageIndex).initState;
2199 }
2200 
setInitState(const ImageIndex & imageIndex,InitState initState)2201 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
2202 {
2203     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2204     // we need to update all the related ImageDescs.
2205     if (imageIndex.isEntireLevelCubeMap())
2206     {
2207         const GLint levelIndex = imageIndex.getLevelIndex();
2208         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2209         {
2210             setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
2211         }
2212     }
2213     else
2214     {
2215         ImageDesc newDesc = mState.getImageDesc(imageIndex);
2216         newDesc.initState = initState;
2217         mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
2218     }
2219 }
2220 
setInitState(InitState initState)2221 void Texture::setInitState(InitState initState)
2222 {
2223     for (ImageDesc &imageDesc : mState.mImageDescs)
2224     {
2225         // Only modify defined images, undefined images will remain in the initialized state
2226         if (!imageDesc.size.empty())
2227         {
2228             imageDesc.initState = initState;
2229         }
2230     }
2231     mState.mInitState = initState;
2232 }
2233 
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const2234 bool Texture::doesSubImageNeedInit(const Context *context,
2235                                    const ImageIndex &imageIndex,
2236                                    const Box &area) const
2237 {
2238     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2239     {
2240         return false;
2241     }
2242 
2243     // Pre-initialize the texture contents if necessary.
2244     const ImageDesc &desc = mState.getImageDesc(imageIndex);
2245     if (desc.initState != InitState::MayNeedInit)
2246     {
2247         return false;
2248     }
2249 
2250     ASSERT(mState.mInitState == InitState::MayNeedInit);
2251     return !area.coversSameExtent(desc.size);
2252 }
2253 
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)2254 angle::Result Texture::ensureSubImageInitialized(const Context *context,
2255                                                  const ImageIndex &imageIndex,
2256                                                  const Box &area)
2257 {
2258     if (doesSubImageNeedInit(context, imageIndex, area))
2259     {
2260         // NOTE: do not optimize this to only initialize the passed area of the texture, or the
2261         // initialization logic in copySubImage will be incorrect.
2262         ANGLE_TRY(initializeContents(context, imageIndex));
2263     }
2264     setInitState(imageIndex, InitState::Initialized);
2265     return angle::Result::Continue;
2266 }
2267 
handleMipmapGenerationHint(Context * context,int level)2268 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
2269 {
2270     if (getGenerateMipmapHint() == GL_TRUE && level == 0)
2271     {
2272         ANGLE_TRY(generateMipmap(context));
2273     }
2274 
2275     return angle::Result::Continue;
2276 }
2277 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)2278 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
2279 {
2280     switch (message)
2281     {
2282         case angle::SubjectMessage::ContentsChanged:
2283             if (index != kBufferSubjectIndex)
2284             {
2285                 // ContentsChange originates from TextureStorage11::resolveAndReleaseTexture
2286                 // which resolves the underlying multisampled texture if it exists and so
2287                 // Texture will signal dirty storage to invalidate its own cache and the
2288                 // attached framebuffer's cache.
2289                 signalDirtyStorage(InitState::Initialized);
2290             }
2291             break;
2292         case angle::SubjectMessage::DirtyBitsFlagged:
2293             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2294 
2295             // Notify siblings that we are dirty.
2296             if (index == rx::kTextureImageImplObserverMessageIndex)
2297             {
2298                 notifySiblings(message);
2299             }
2300             break;
2301         case angle::SubjectMessage::SubjectChanged:
2302             mState.mInitState = InitState::MayNeedInit;
2303             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2304             onStateChange(angle::SubjectMessage::ContentsChanged);
2305 
2306             // Notify siblings that we are dirty.
2307             if (index == rx::kTextureImageImplObserverMessageIndex)
2308             {
2309                 notifySiblings(message);
2310             }
2311             else if (index == kBufferSubjectIndex)
2312             {
2313                 const gl::Buffer *buffer = mState.mBuffer.get();
2314                 ASSERT(buffer != nullptr);
2315 
2316                 // Update cached image desc based on buffer size.
2317                 GLsizeiptr size = GetBoundBufferAvailableSize(mState.mBuffer);
2318 
2319                 ImageDesc desc          = mState.getImageDesc(TextureTarget::Buffer, 0);
2320                 const GLuint pixelBytes = desc.format.info->pixelBytes;
2321                 desc.size.width         = static_cast<GLuint>(size / pixelBytes);
2322 
2323                 mState.setImageDesc(TextureTarget::Buffer, 0, desc);
2324             }
2325             break;
2326         case angle::SubjectMessage::StorageReleased:
2327             // When the TextureStorage is released, it needs to update the
2328             // RenderTargetCache of the Framebuffer attaching this Texture.
2329             // This is currently only for D3D back-end. See http://crbug.com/1234829
2330             if (index == rx::kTextureImageImplObserverMessageIndex)
2331             {
2332                 onStateChange(angle::SubjectMessage::StorageReleased);
2333             }
2334             break;
2335         case angle::SubjectMessage::SubjectMapped:
2336         case angle::SubjectMessage::SubjectUnmapped:
2337         case angle::SubjectMessage::BindingChanged:
2338             ASSERT(index == kBufferSubjectIndex);
2339             break;
2340         case angle::SubjectMessage::InitializationComplete:
2341             ASSERT(index == rx::kTextureImageImplObserverMessageIndex);
2342             setInitState(InitState::Initialized);
2343             break;
2344         case angle::SubjectMessage::InternalMemoryAllocationChanged:
2345             // Need to mark the texture dirty to give the back end a chance to handle the new
2346             // buffer. For example, the Vulkan back end needs to create a new buffer view that
2347             // points to the newly allocated buffer and update the texture descriptor set.
2348             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2349             break;
2350         //cve-2022-0297 angle
2351         case angle::SubjectMessage::BufferVkStorageChanged:
2352             break;
2353         default:
2354             UNREACHABLE();
2355             break;
2356     }
2357 }
2358 
getImplementationColorReadFormat(const Context * context) const2359 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
2360 {
2361     return mTexture->getColorReadFormat(context);
2362 }
2363 
getImplementationColorReadType(const Context * context) const2364 GLenum Texture::getImplementationColorReadType(const Context *context) const
2365 {
2366     return mTexture->getColorReadType(context);
2367 }
2368 
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)2369 angle::Result Texture::getTexImage(const Context *context,
2370                                    const PixelPackState &packState,
2371                                    Buffer *packBuffer,
2372                                    TextureTarget target,
2373                                    GLint level,
2374                                    GLenum format,
2375                                    GLenum type,
2376                                    void *pixels)
2377 {
2378     // No-op if the image level is empty.
2379     if (getExtents(target, level).empty())
2380     {
2381         return angle::Result::Continue;
2382     }
2383 
2384     return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
2385                                  pixels);
2386 }
2387 
getCompressedTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,void * pixels)2388 angle::Result Texture::getCompressedTexImage(const Context *context,
2389                                              const PixelPackState &packState,
2390                                              Buffer *packBuffer,
2391                                              TextureTarget target,
2392                                              GLint level,
2393                                              void *pixels)
2394 {
2395     // No-op if the image level is empty.
2396     if (getExtents(target, level).empty())
2397     {
2398         return angle::Result::Continue;
2399     }
2400 
2401     return mTexture->getCompressedTexImage(context, packState, packBuffer, target, level, pixels);
2402 }
2403 
onBindAsImageTexture()2404 void Texture::onBindAsImageTexture()
2405 {
2406     if (!mState.mHasBeenBoundAsImage)
2407     {
2408         mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2409         mState.mHasBeenBoundAsImage = true;
2410     }
2411 }
2412 
2413 }  // namespace gl
2414