• 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     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1193 }
1194 
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)1195 angle::Result Texture::setImage(Context *context,
1196                                 const PixelUnpackState &unpackState,
1197                                 Buffer *unpackBuffer,
1198                                 TextureTarget target,
1199                                 GLint level,
1200                                 GLenum internalFormat,
1201                                 const Extents &size,
1202                                 GLenum format,
1203                                 GLenum type,
1204                                 const uint8_t *pixels)
1205 {
1206     ASSERT(TextureTargetToType(target) == mState.mType);
1207 
1208     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1209     ANGLE_TRY(releaseTexImageInternal(context));
1210 
1211     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1212     ANGLE_TRY(orphanImages(context, &releaseImage));
1213 
1214     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1215 
1216     ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1217                                  unpackBuffer, pixels));
1218 
1219     InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1220     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1221 
1222     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1223 
1224     signalDirtyStorage(initState);
1225 
1226     return angle::Result::Continue;
1227 }
1228 
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1229 angle::Result Texture::setSubImage(Context *context,
1230                                    const PixelUnpackState &unpackState,
1231                                    Buffer *unpackBuffer,
1232                                    TextureTarget target,
1233                                    GLint level,
1234                                    const Box &area,
1235                                    GLenum format,
1236                                    GLenum type,
1237                                    const uint8_t *pixels)
1238 {
1239     ASSERT(TextureTargetToType(target) == mState.mType);
1240 
1241     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1242     ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1243 
1244     ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1245                                     pixels));
1246 
1247     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1248 
1249     onStateChange(angle::SubjectMessage::ContentsChanged);
1250 
1251     return angle::Result::Continue;
1252 }
1253 
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1254 angle::Result Texture::setCompressedImage(Context *context,
1255                                           const PixelUnpackState &unpackState,
1256                                           TextureTarget target,
1257                                           GLint level,
1258                                           GLenum internalFormat,
1259                                           const Extents &size,
1260                                           size_t imageSize,
1261                                           const uint8_t *pixels)
1262 {
1263     ASSERT(TextureTargetToType(target) == mState.mType);
1264 
1265     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1266     ANGLE_TRY(releaseTexImageInternal(context));
1267 
1268     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1269     ANGLE_TRY(orphanImages(context, &releaseImage));
1270 
1271     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1272 
1273     ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1274                                            imageSize, pixels));
1275 
1276     Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1277 
1278     InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1279     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1280     signalDirtyStorage(initState);
1281 
1282     return angle::Result::Continue;
1283 }
1284 
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1285 angle::Result Texture::setCompressedSubImage(const Context *context,
1286                                              const PixelUnpackState &unpackState,
1287                                              TextureTarget target,
1288                                              GLint level,
1289                                              const Box &area,
1290                                              GLenum format,
1291                                              size_t imageSize,
1292                                              const uint8_t *pixels)
1293 {
1294     ASSERT(TextureTargetToType(target) == mState.mType);
1295 
1296     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1297     ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1298 
1299     ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1300                                               pixels));
1301 
1302     onStateChange(angle::SubjectMessage::ContentsChanged);
1303 
1304     return angle::Result::Continue;
1305 }
1306 
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1307 angle::Result Texture::copyImage(Context *context,
1308                                  TextureTarget target,
1309                                  GLint level,
1310                                  const Rectangle &sourceArea,
1311                                  GLenum internalFormat,
1312                                  Framebuffer *source)
1313 {
1314     ASSERT(TextureTargetToType(target) == mState.mType);
1315 
1316     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1317     ANGLE_TRY(releaseTexImageInternal(context));
1318 
1319     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1320     ANGLE_TRY(orphanImages(context, &releaseImage));
1321 
1322     ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1323 
1324     const InternalFormat &internalFormatInfo =
1325         GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1326 
1327     // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1328     // other pixels untouched. For safety in robust resource initialization, assume that that
1329     // clipping is going to occur when computing the region for which to ensure initialization. If
1330     // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1331     // going to be set during the copy operation.
1332     Box destBox;
1333     bool forceCopySubImage = false;
1334     if (context->isRobustResourceInitEnabled())
1335     {
1336         const FramebufferAttachment *sourceReadAttachment = source->getReadColorAttachment();
1337         Extents fbSize                                    = sourceReadAttachment->getSize();
1338         // Force using copySubImage when the source area is out of bounds AND
1339         // we're not copying to and from the same texture
1340         forceCopySubImage = ((sourceArea.x < 0) || (sourceArea.y < 0) ||
1341                              ((sourceArea.x + sourceArea.width) > fbSize.width) ||
1342                              ((sourceArea.y + sourceArea.height) > fbSize.height)) &&
1343                             (sourceReadAttachment->getResource() != this);
1344         Rectangle clippedArea;
1345         if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1346         {
1347             const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1348                                        0);
1349             destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1350                           clippedArea.height, 1);
1351         }
1352     }
1353 
1354     InitState initState = DetermineInitState(context, nullptr, nullptr);
1355 
1356     // If we need to initialize the destination texture we split the call into a create call,
1357     // an initializeContents call, and then a copySubImage call. This ensures the destination
1358     // texture exists before we try to clear it.
1359     Extents size(sourceArea.width, sourceArea.height, 1);
1360     if (forceCopySubImage || doesSubImageNeedInit(context, index, destBox))
1361     {
1362         ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1363                                      internalFormatInfo.format, internalFormatInfo.type,
1364                                      PixelUnpackState(), nullptr, nullptr));
1365         mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormatInfo), initState));
1366         ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1367         ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1368     }
1369     else
1370     {
1371         ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1372     }
1373 
1374     mState.setImageDesc(target, level,
1375                         ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1376 
1377     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1378 
1379     // Because this could affect the texture storage we might need to init other layers/levels.
1380     signalDirtyStorage(initState);
1381 
1382     return angle::Result::Continue;
1383 }
1384 
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1385 angle::Result Texture::copySubImage(Context *context,
1386                                     const ImageIndex &index,
1387                                     const Offset &destOffset,
1388                                     const Rectangle &sourceArea,
1389                                     Framebuffer *source)
1390 {
1391     ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1392 
1393     // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1394     // other pixels untouched. For safety in robust resource initialization, assume that that
1395     // clipping is going to occur when computing the region for which to ensure initialization. If
1396     // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1397     // going to be set during the copy operation. Note that this assumes that
1398     // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1399     // just a sub-region.
1400     Box destBox;
1401     if (context->isRobustResourceInitEnabled())
1402     {
1403         Extents fbSize = source->getReadColorAttachment()->getSize();
1404         Rectangle clippedArea;
1405         if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1406         {
1407             const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1408                                        destOffset.y + clippedArea.y - sourceArea.y, 0);
1409             destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1410                           clippedArea.height, 1);
1411         }
1412     }
1413 
1414     ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1415 
1416     ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1417     ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1418 
1419     onStateChange(angle::SubjectMessage::ContentsChanged);
1420 
1421     return angle::Result::Continue;
1422 }
1423 
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)1424 angle::Result Texture::copyRenderbufferSubData(Context *context,
1425                                                const gl::Renderbuffer *srcBuffer,
1426                                                GLint srcLevel,
1427                                                GLint srcX,
1428                                                GLint srcY,
1429                                                GLint srcZ,
1430                                                GLint dstLevel,
1431                                                GLint dstX,
1432                                                GLint dstY,
1433                                                GLint dstZ,
1434                                                GLsizei srcWidth,
1435                                                GLsizei srcHeight,
1436                                                GLsizei srcDepth)
1437 {
1438     ANGLE_TRY(mTexture->copyRenderbufferSubData(context, srcBuffer, srcLevel, srcX, srcY, srcZ,
1439                                                 dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1440                                                 srcDepth));
1441 
1442     signalDirtyStorage(InitState::Initialized);
1443 
1444     return angle::Result::Continue;
1445 }
1446 
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)1447 angle::Result Texture::copyTextureSubData(Context *context,
1448                                           const gl::Texture *srcTexture,
1449                                           GLint srcLevel,
1450                                           GLint srcX,
1451                                           GLint srcY,
1452                                           GLint srcZ,
1453                                           GLint dstLevel,
1454                                           GLint dstX,
1455                                           GLint dstY,
1456                                           GLint dstZ,
1457                                           GLsizei srcWidth,
1458                                           GLsizei srcHeight,
1459                                           GLsizei srcDepth)
1460 {
1461     ANGLE_TRY(mTexture->copyTextureSubData(context, srcTexture, srcLevel, srcX, srcY, srcZ,
1462                                            dstLevel, dstX, dstY, dstZ, srcWidth, srcHeight,
1463                                            srcDepth));
1464 
1465     signalDirtyStorage(InitState::Initialized);
1466 
1467     return angle::Result::Continue;
1468 }
1469 
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1470 angle::Result Texture::copyTexture(Context *context,
1471                                    TextureTarget target,
1472                                    GLint level,
1473                                    GLenum internalFormat,
1474                                    GLenum type,
1475                                    GLint sourceLevel,
1476                                    bool unpackFlipY,
1477                                    bool unpackPremultiplyAlpha,
1478                                    bool unpackUnmultiplyAlpha,
1479                                    Texture *source)
1480 {
1481     ASSERT(TextureTargetToType(target) == mState.mType);
1482     ASSERT(source->getType() != TextureType::CubeMap);
1483 
1484     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1485     ANGLE_TRY(releaseTexImageInternal(context));
1486 
1487     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1488     ANGLE_TRY(orphanImages(context, &releaseImage));
1489 
1490     // Initialize source texture.
1491     // Note: we don't have a way to notify which portions of the image changed currently.
1492     ANGLE_TRY(source->ensureInitialized(context));
1493 
1494     ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1495 
1496     ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1497                                     unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1498 
1499     const auto &sourceDesc =
1500         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), sourceLevel);
1501     const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1502     mState.setImageDesc(
1503         target, level,
1504         ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1505 
1506     signalDirtyStorage(InitState::Initialized);
1507 
1508     return angle::Result::Continue;
1509 }
1510 
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1511 angle::Result Texture::copySubTexture(const Context *context,
1512                                       TextureTarget target,
1513                                       GLint level,
1514                                       const Offset &destOffset,
1515                                       GLint sourceLevel,
1516                                       const Box &sourceBox,
1517                                       bool unpackFlipY,
1518                                       bool unpackPremultiplyAlpha,
1519                                       bool unpackUnmultiplyAlpha,
1520                                       Texture *source)
1521 {
1522     ASSERT(TextureTargetToType(target) == mState.mType);
1523 
1524     // Ensure source is initialized.
1525     ANGLE_TRY(source->ensureInitialized(context));
1526 
1527     Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1528                 sourceBox.depth);
1529     ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1530     ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1531 
1532     ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1533                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1534                                        source));
1535 
1536     onStateChange(angle::SubjectMessage::ContentsChanged);
1537 
1538     return angle::Result::Continue;
1539 }
1540 
copyCompressedTexture(Context * context,const Texture * source)1541 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1542 {
1543     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1544     ANGLE_TRY(releaseTexImageInternal(context));
1545 
1546     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1547     ANGLE_TRY(orphanImages(context, &releaseImage));
1548 
1549     ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1550 
1551     ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1552     const auto &sourceDesc =
1553         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1554     mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1555 
1556     return angle::Result::Continue;
1557 }
1558 
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1559 angle::Result Texture::setStorage(Context *context,
1560                                   TextureType type,
1561                                   GLsizei levels,
1562                                   GLenum internalFormat,
1563                                   const Extents &size)
1564 {
1565     ASSERT(type == mState.mType);
1566 
1567     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1568     ANGLE_TRY(releaseTexImageInternal(context));
1569 
1570     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1571     ANGLE_TRY(orphanImages(context, &releaseImage));
1572 
1573     mState.mImmutableFormat = true;
1574     mState.mImmutableLevels = static_cast<GLuint>(levels);
1575     mState.clearImageDescs();
1576     InitState initState = DetermineInitState(context, nullptr, nullptr);
1577     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1578                              initState);
1579 
1580     ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1581 
1582     // Changing the texture to immutable can trigger a change in the base and max levels:
1583     // GLES 3.0.4 section 3.8.10 pg 158:
1584     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1585     // clamped to the range[levelbase;levels].
1586     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1587     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1588 
1589     signalDirtyStorage(initState);
1590 
1591     return angle::Result::Continue;
1592 }
1593 
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1594 angle::Result Texture::setImageExternal(Context *context,
1595                                         TextureTarget target,
1596                                         GLint level,
1597                                         GLenum internalFormat,
1598                                         const Extents &size,
1599                                         GLenum format,
1600                                         GLenum type)
1601 {
1602     ASSERT(TextureTargetToType(target) == mState.mType);
1603 
1604     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1605     ANGLE_TRY(releaseTexImageInternal(context));
1606 
1607     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1608     ANGLE_TRY(orphanImages(context, &releaseImage));
1609 
1610     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1611 
1612     ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1613 
1614     InitState initState = InitState::Initialized;
1615     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1616 
1617     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1618 
1619     signalDirtyStorage(initState);
1620 
1621     return angle::Result::Continue;
1622 }
1623 
setStorageMultisample(Context * context,TextureType type,GLsizei samplesIn,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1624 angle::Result Texture::setStorageMultisample(Context *context,
1625                                              TextureType type,
1626                                              GLsizei samplesIn,
1627                                              GLint internalFormat,
1628                                              const Extents &size,
1629                                              bool fixedSampleLocations)
1630 {
1631     ASSERT(type == mState.mType);
1632 
1633     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1634     ANGLE_TRY(releaseTexImageInternal(context));
1635 
1636     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1637     ANGLE_TRY(orphanImages(context, &releaseImage));
1638 
1639     // Potentially adjust "samples" to a supported value
1640     const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1641     GLsizei samples               = formatCaps.getNearestSamples(samplesIn);
1642 
1643     mState.mImmutableFormat = true;
1644     mState.mImmutableLevels = static_cast<GLuint>(1);
1645     mState.clearImageDescs();
1646     InitState initState = DetermineInitState(context, nullptr, nullptr);
1647     mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1648                                         initState);
1649 
1650     ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1651                                               fixedSampleLocations));
1652     signalDirtyStorage(initState);
1653 
1654     return angle::Result::Continue;
1655 }
1656 
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset,GLbitfield createFlags,GLbitfield usageFlags,const void * imageCreateInfoPNext)1657 angle::Result Texture::setStorageExternalMemory(Context *context,
1658                                                 TextureType type,
1659                                                 GLsizei levels,
1660                                                 GLenum internalFormat,
1661                                                 const Extents &size,
1662                                                 MemoryObject *memoryObject,
1663                                                 GLuint64 offset,
1664                                                 GLbitfield createFlags,
1665                                                 GLbitfield usageFlags,
1666                                                 const void *imageCreateInfoPNext)
1667 {
1668     ASSERT(type == mState.mType);
1669 
1670     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1671     ANGLE_TRY(releaseTexImageInternal(context));
1672 
1673     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1674     ANGLE_TRY(orphanImages(context, &releaseImage));
1675 
1676     ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1677                                                  memoryObject, offset, createFlags, usageFlags,
1678                                                  imageCreateInfoPNext));
1679 
1680     mState.mImmutableFormat = true;
1681     mState.mImmutableLevels = static_cast<GLuint>(levels);
1682     mState.clearImageDescs();
1683     InitState initState = DetermineInitState(context, nullptr, nullptr);
1684     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1685                              initState);
1686 
1687     // Changing the texture to immutable can trigger a change in the base and max levels:
1688     // GLES 3.0.4 section 3.8.10 pg 158:
1689     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1690     // clamped to the range[levelbase;levels].
1691     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1692     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1693 
1694     signalDirtyStorage(initState);
1695 
1696     return angle::Result::Continue;
1697 }
1698 
generateMipmap(Context * context)1699 angle::Result Texture::generateMipmap(Context *context)
1700 {
1701     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1702     ANGLE_TRY(releaseTexImageInternal(context));
1703 
1704     // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1705     // is not mip complete.
1706     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1707     if (!isMipmapComplete())
1708     {
1709         ANGLE_TRY(orphanImages(context, &releaseImage));
1710     }
1711 
1712     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1713     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1714 
1715     if (maxLevel <= baseLevel)
1716     {
1717         return angle::Result::Continue;
1718     }
1719 
1720     // If any dimension is zero, this is a no-op:
1721     //
1722     // > Otherwise, if level_base is not defined, or if any dimension is zero, all mipmap levels are
1723     // > left unchanged. This is not an error.
1724     const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1725     if (baseImageInfo.size.empty())
1726     {
1727         return angle::Result::Continue;
1728     }
1729 
1730     // Clear the base image(s) immediately if needed
1731     if (context->isRobustResourceInitEnabled())
1732     {
1733         ImageIndexIterator it =
1734             ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1735                                             ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1736         while (it.hasNext())
1737         {
1738             const ImageIndex index = it.next();
1739             const ImageDesc &desc  = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1740 
1741             if (desc.initState == InitState::MayNeedInit)
1742             {
1743                 ANGLE_TRY(initializeContents(context, index));
1744             }
1745         }
1746     }
1747 
1748     ANGLE_TRY(syncState(context, Command::GenerateMipmap));
1749     ANGLE_TRY(mTexture->generateMipmap(context));
1750 
1751     // Propagate the format and size of the base mip to the smaller ones. Cube maps are guaranteed
1752     // to have faces of the same size and format so any faces can be picked.
1753     mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1754                              InitState::Initialized);
1755 
1756     signalDirtyStorage(InitState::Initialized);
1757 
1758     return angle::Result::Continue;
1759 }
1760 
bindTexImageFromSurface(Context * context,egl::Surface * surface)1761 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1762 {
1763     ASSERT(surface);
1764 
1765     if (mBoundSurface)
1766     {
1767         ANGLE_TRY(releaseTexImageFromSurface(context));
1768     }
1769 
1770     ANGLE_TRY(mTexture->bindTexImage(context, surface));
1771     mBoundSurface = surface;
1772 
1773     // Set the image info to the size and format of the surface
1774     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1775     Extents size(surface->getWidth(), surface->getHeight(), 1);
1776     ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1777     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1778     mState.mHasProtectedContent = surface->hasProtectedContent();
1779     signalDirtyStorage(InitState::Initialized);
1780     return angle::Result::Continue;
1781 }
1782 
releaseTexImageFromSurface(const Context * context)1783 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1784 {
1785     ASSERT(mBoundSurface);
1786     mBoundSurface = nullptr;
1787     ANGLE_TRY(mTexture->releaseTexImage(context));
1788 
1789     // Erase the image info for level 0
1790     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1791     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1792     mState.mHasProtectedContent = false;
1793     signalDirtyStorage(InitState::Initialized);
1794     return angle::Result::Continue;
1795 }
1796 
bindStream(egl::Stream * stream)1797 void Texture::bindStream(egl::Stream *stream)
1798 {
1799     ASSERT(stream);
1800 
1801     // It should not be possible to bind a texture already bound to another stream
1802     ASSERT(mBoundStream == nullptr);
1803 
1804     mBoundStream = stream;
1805 
1806     ASSERT(mState.mType == TextureType::External);
1807 }
1808 
releaseStream()1809 void Texture::releaseStream()
1810 {
1811     ASSERT(mBoundStream);
1812     mBoundStream = nullptr;
1813 }
1814 
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1815 angle::Result Texture::acquireImageFromStream(const Context *context,
1816                                               const egl::Stream::GLTextureDescription &desc)
1817 {
1818     ASSERT(mBoundStream != nullptr);
1819     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1820 
1821     Extents size(desc.width, desc.height, 1);
1822     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1823                         ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1824     signalDirtyStorage(InitState::Initialized);
1825     return angle::Result::Continue;
1826 }
1827 
releaseImageFromStream(const Context * context)1828 angle::Result Texture::releaseImageFromStream(const Context *context)
1829 {
1830     ASSERT(mBoundStream != nullptr);
1831     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1832                                          egl::Stream::GLTextureDescription()));
1833 
1834     // Set to incomplete
1835     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1836     signalDirtyStorage(InitState::Initialized);
1837     return angle::Result::Continue;
1838 }
1839 
releaseTexImageInternal(Context * context)1840 angle::Result Texture::releaseTexImageInternal(Context *context)
1841 {
1842     if (mBoundSurface)
1843     {
1844         // Notify the surface
1845         egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1846         // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1847         if (eglErr.isError())
1848         {
1849             context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1850                                  __FILE__, ANGLE_FUNCTION, __LINE__);
1851         }
1852 
1853         // Then, call the same method as from the surface
1854         ANGLE_TRY(releaseTexImageFromSurface(context));
1855     }
1856     return angle::Result::Continue;
1857 }
1858 
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1859 angle::Result Texture::setEGLImageTarget(Context *context,
1860                                          TextureType type,
1861                                          egl::Image *imageTarget)
1862 {
1863     ASSERT(type == mState.mType);
1864     ASSERT(type == TextureType::_2D || type == TextureType::External ||
1865            type == TextureType::_2DArray);
1866 
1867     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1868     ANGLE_TRY(releaseTexImageInternal(context));
1869 
1870     egl::RefCountObjectReleaser<egl::Image> releaseImage;
1871     ANGLE_TRY(orphanImages(context, &releaseImage));
1872 
1873     ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1874 
1875     setTargetImage(context, imageTarget);
1876 
1877     Extents size(static_cast<int>(imageTarget->getWidth()),
1878                  static_cast<int>(imageTarget->getHeight()), 1);
1879 
1880     auto initState = imageTarget->sourceInitState();
1881 
1882     mState.clearImageDescs();
1883     mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1884                         ImageDesc(size, imageTarget->getFormat(), initState));
1885     mState.mHasProtectedContent = imageTarget->hasProtectedContent();
1886     signalDirtyStorage(initState);
1887 
1888     return angle::Result::Continue;
1889 }
1890 
getAttachmentSize(const ImageIndex & imageIndex) const1891 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1892 {
1893     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1894     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1895     // one that belongs to the first face of the cube map.
1896     if (imageIndex.isEntireLevelCubeMap())
1897     {
1898         // A cube map texture is cube complete if the following conditions all hold true:
1899         // - The levelbase arrays of each of the six texture images making up the cube map have
1900         //   identical, positive, and square dimensions.
1901         if (!mState.isCubeComplete())
1902         {
1903             return Extents();
1904         }
1905     }
1906 
1907     return mState.getImageDesc(imageIndex).size;
1908 }
1909 
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1910 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1911 {
1912     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1913     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1914     // one that belongs to the first face of the cube map.
1915     if (imageIndex.isEntireLevelCubeMap())
1916     {
1917         // A cube map texture is cube complete if the following conditions all hold true:
1918         // - The levelbase arrays were each specified with the same effective internal format.
1919         if (!mState.isCubeComplete())
1920         {
1921             return Format::Invalid();
1922         }
1923     }
1924     return mState.getImageDesc(imageIndex).format;
1925 }
1926 
getAttachmentSamples(const ImageIndex & imageIndex) const1927 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1928 {
1929     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1930     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1931     if (imageIndex.isEntireLevelCubeMap())
1932     {
1933         return 0;
1934     }
1935 
1936     return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1937 }
1938 
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1939 bool Texture::isRenderable(const Context *context,
1940                            GLenum binding,
1941                            const ImageIndex &imageIndex) const
1942 {
1943     if (isEGLImageTarget())
1944     {
1945         return ImageSibling::isRenderable(context, binding, imageIndex);
1946     }
1947 
1948     // Surfaces bound to textures are always renderable. This avoids issues with surfaces with ES3+
1949     // formats not being renderable when bound to textures in ES2 contexts.
1950     if (mBoundSurface)
1951     {
1952         return true;
1953     }
1954 
1955     return getAttachmentFormat(binding, imageIndex)
1956         .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1957 }
1958 
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1959 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1960 {
1961     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1962     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1963     if (imageIndex.isEntireLevelCubeMap())
1964     {
1965         return true;
1966     }
1967 
1968     // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1969     // the same for all attached textures.
1970     return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1971 }
1972 
setBorderColor(const Context * context,const ColorGeneric & color)1973 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1974 {
1975     mState.mSamplerState.setBorderColor(color);
1976     signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1977 }
1978 
getBorderColor() const1979 const ColorGeneric &Texture::getBorderColor() const
1980 {
1981     return mState.mSamplerState.getBorderColor();
1982 }
1983 
getRequiredTextureImageUnits(const Context * context) const1984 GLint Texture::getRequiredTextureImageUnits(const Context *context) const
1985 {
1986     // Only external texture types can return non-1.
1987     if (mState.mType != TextureType::External)
1988     {
1989         return 1;
1990     }
1991 
1992     return mTexture->getRequiredExternalTextureImageUnits(context);
1993 }
1994 
setCrop(const Rectangle & rect)1995 void Texture::setCrop(const Rectangle &rect)
1996 {
1997     mState.setCrop(rect);
1998 }
1999 
getCrop() const2000 const Rectangle &Texture::getCrop() const
2001 {
2002     return mState.getCrop();
2003 }
2004 
setGenerateMipmapHint(GLenum hint)2005 void Texture::setGenerateMipmapHint(GLenum hint)
2006 {
2007     mState.setGenerateMipmapHint(hint);
2008 }
2009 
getGenerateMipmapHint() const2010 GLenum Texture::getGenerateMipmapHint() const
2011 {
2012     return mState.getGenerateMipmapHint();
2013 }
2014 
setBuffer(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat)2015 angle::Result Texture::setBuffer(const gl::Context *context,
2016                                  gl::Buffer *buffer,
2017                                  GLenum internalFormat)
2018 {
2019     // Use 0 to indicate that the size is taken from whatever size the buffer has when the texture
2020     // buffer is used.
2021     return setBufferRange(context, buffer, internalFormat, 0, 0);
2022 }
2023 
setBufferRange(const gl::Context * context,gl::Buffer * buffer,GLenum internalFormat,GLintptr offset,GLsizeiptr size)2024 angle::Result Texture::setBufferRange(const gl::Context *context,
2025                                       gl::Buffer *buffer,
2026                                       GLenum internalFormat,
2027                                       GLintptr offset,
2028                                       GLsizeiptr size)
2029 {
2030     mState.mImmutableFormat = true;
2031     mState.mBuffer.set(context, buffer, offset, size);
2032     ANGLE_TRY(mTexture->setBuffer(context, internalFormat));
2033 
2034     mState.clearImageDescs();
2035     if (buffer == nullptr)
2036     {
2037         mBufferObserver.reset();
2038         InitState initState = DetermineInitState(context, nullptr, nullptr);
2039         signalDirtyStorage(initState);
2040         return angle::Result::Continue;
2041     }
2042 
2043     size = GetBoundBufferAvailableSize(mState.mBuffer);
2044 
2045     mState.mImmutableLevels           = static_cast<GLuint>(1);
2046     InternalFormat internalFormatInfo = GetSizedInternalFormatInfo(internalFormat);
2047     Format format(internalFormat);
2048     Extents extents(static_cast<GLuint>(size / internalFormatInfo.pixelBytes), 1, 1);
2049     InitState initState = buffer->initState();
2050     mState.setImageDesc(TextureTarget::Buffer, 0, ImageDesc(extents, format, initState));
2051 
2052     signalDirtyStorage(initState);
2053 
2054     // Observe modifications to the buffer, so that extents can be updated.
2055     mBufferObserver.bind(buffer);
2056 
2057     return angle::Result::Continue;
2058 }
2059 
getBuffer() const2060 const OffsetBindingPointer<Buffer> &Texture::getBuffer() const
2061 {
2062     return mState.mBuffer;
2063 }
2064 
onAttach(const Context * context,rx::Serial framebufferSerial)2065 void Texture::onAttach(const Context *context, rx::Serial framebufferSerial)
2066 {
2067     addRef();
2068 
2069     // Duplicates allowed for multiple attachment points. See the comment in the header.
2070     mBoundFramebufferSerials.push_back(framebufferSerial);
2071 
2072     if (!mState.mHasBeenBoundAsAttachment)
2073     {
2074         mDirtyBits.set(DIRTY_BIT_BOUND_AS_ATTACHMENT);
2075         mState.mHasBeenBoundAsAttachment = true;
2076     }
2077 }
2078 
onDetach(const Context * context,rx::Serial framebufferSerial)2079 void Texture::onDetach(const Context *context, rx::Serial framebufferSerial)
2080 {
2081     // Erase first instance. If there are multiple bindings, leave the others.
2082     ASSERT(isBoundToFramebuffer(framebufferSerial));
2083     mBoundFramebufferSerials.remove_and_permute(framebufferSerial);
2084 
2085     release(context);
2086 }
2087 
getId() const2088 GLuint Texture::getId() const
2089 {
2090     return id().value;
2091 }
2092 
getNativeID() const2093 GLuint Texture::getNativeID() const
2094 {
2095     return mTexture->getNativeID();
2096 }
2097 
syncState(const Context * context,Command source)2098 angle::Result Texture::syncState(const Context *context, Command source)
2099 {
2100     ASSERT(hasAnyDirtyBit() || source == Command::GenerateMipmap);
2101     ANGLE_TRY(mTexture->syncState(context, mDirtyBits, source));
2102     mDirtyBits.reset();
2103     mState.mInitState = InitState::Initialized;
2104     return angle::Result::Continue;
2105 }
2106 
getAttachmentImpl() const2107 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
2108 {
2109     return mTexture;
2110 }
2111 
isSamplerComplete(const Context * context,const Sampler * optionalSampler)2112 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
2113 {
2114     const auto &samplerState =
2115         optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
2116     const auto &contextState = context->getState();
2117 
2118     if (contextState.getContextID() != mCompletenessCache.context ||
2119         !mCompletenessCache.samplerState.sameCompleteness(samplerState))
2120     {
2121         mCompletenessCache.context      = context->getState().getContextID();
2122         mCompletenessCache.samplerState = samplerState;
2123         mCompletenessCache.samplerComplete =
2124             mState.computeSamplerCompleteness(samplerState, contextState);
2125     }
2126 
2127     return mCompletenessCache.samplerComplete;
2128 }
2129 
SamplerCompletenessCache()2130 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
2131     : context({0}), samplerState(), samplerComplete(false)
2132 {}
2133 
invalidateCompletenessCache() const2134 void Texture::invalidateCompletenessCache() const
2135 {
2136     mCompletenessCache.context = {0};
2137 }
2138 
ensureInitialized(const Context * context)2139 angle::Result Texture::ensureInitialized(const Context *context)
2140 {
2141     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2142     {
2143         return angle::Result::Continue;
2144     }
2145 
2146     bool anyDirty = false;
2147 
2148     ImageIndexIterator it =
2149         ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
2150                                         ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
2151     while (it.hasNext())
2152     {
2153         const ImageIndex index = it.next();
2154         ImageDesc &desc =
2155             mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
2156         if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
2157         {
2158             ASSERT(mState.mInitState == InitState::MayNeedInit);
2159             ANGLE_TRY(initializeContents(context, index));
2160             desc.initState = InitState::Initialized;
2161             anyDirty       = true;
2162         }
2163     }
2164     if (anyDirty)
2165     {
2166         signalDirtyStorage(InitState::Initialized);
2167     }
2168     mState.mInitState = InitState::Initialized;
2169 
2170     return angle::Result::Continue;
2171 }
2172 
initState(const ImageIndex & imageIndex) const2173 InitState Texture::initState(const ImageIndex &imageIndex) const
2174 {
2175     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2176     // we need to check all the related ImageDescs.
2177     if (imageIndex.isEntireLevelCubeMap())
2178     {
2179         const GLint levelIndex = imageIndex.getLevelIndex();
2180         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2181         {
2182             if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
2183             {
2184                 return InitState::MayNeedInit;
2185             }
2186         }
2187         return InitState::Initialized;
2188     }
2189 
2190     return mState.getImageDesc(imageIndex).initState;
2191 }
2192 
setInitState(const ImageIndex & imageIndex,InitState initState)2193 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
2194 {
2195     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
2196     // we need to update all the related ImageDescs.
2197     if (imageIndex.isEntireLevelCubeMap())
2198     {
2199         const GLint levelIndex = imageIndex.getLevelIndex();
2200         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
2201         {
2202             setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
2203         }
2204     }
2205     else
2206     {
2207         ImageDesc newDesc = mState.getImageDesc(imageIndex);
2208         newDesc.initState = initState;
2209         mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
2210     }
2211 }
2212 
setInitState(InitState initState)2213 void Texture::setInitState(InitState initState)
2214 {
2215     for (ImageDesc &imageDesc : mState.mImageDescs)
2216     {
2217         // Only modify defined images, undefined images will remain in the initialized state
2218         if (!imageDesc.size.empty())
2219         {
2220             imageDesc.initState = initState;
2221         }
2222     }
2223     mState.mInitState = initState;
2224 }
2225 
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const2226 bool Texture::doesSubImageNeedInit(const Context *context,
2227                                    const ImageIndex &imageIndex,
2228                                    const Box &area) const
2229 {
2230     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
2231     {
2232         return false;
2233     }
2234 
2235     // Pre-initialize the texture contents if necessary.
2236     const ImageDesc &desc = mState.getImageDesc(imageIndex);
2237     if (desc.initState != InitState::MayNeedInit)
2238     {
2239         return false;
2240     }
2241 
2242     ASSERT(mState.mInitState == InitState::MayNeedInit);
2243     return !area.coversSameExtent(desc.size);
2244 }
2245 
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)2246 angle::Result Texture::ensureSubImageInitialized(const Context *context,
2247                                                  const ImageIndex &imageIndex,
2248                                                  const Box &area)
2249 {
2250     if (doesSubImageNeedInit(context, imageIndex, area))
2251     {
2252         // NOTE: do not optimize this to only initialize the passed area of the texture, or the
2253         // initialization logic in copySubImage will be incorrect.
2254         ANGLE_TRY(initializeContents(context, imageIndex));
2255     }
2256     setInitState(imageIndex, InitState::Initialized);
2257     return angle::Result::Continue;
2258 }
2259 
handleMipmapGenerationHint(Context * context,int level)2260 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
2261 {
2262     if (getGenerateMipmapHint() == GL_TRUE && level == 0)
2263     {
2264         ANGLE_TRY(generateMipmap(context));
2265     }
2266 
2267     return angle::Result::Continue;
2268 }
2269 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)2270 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
2271 {
2272     switch (message)
2273     {
2274         case angle::SubjectMessage::ContentsChanged:
2275             if (index != kBufferSubjectIndex)
2276             {
2277                 // ContentsChange originates from TextureStorage11::resolveAndReleaseTexture
2278                 // which resolves the underlying multisampled texture if it exists and so
2279                 // Texture will signal dirty storage to invalidate its own cache and the
2280                 // attached framebuffer's cache.
2281                 signalDirtyStorage(InitState::Initialized);
2282             }
2283             break;
2284         case angle::SubjectMessage::DirtyBitsFlagged:
2285             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2286 
2287             // Notify siblings that we are dirty.
2288             if (index == rx::kTextureImageImplObserverMessageIndex)
2289             {
2290                 notifySiblings(message);
2291             }
2292             break;
2293         case angle::SubjectMessage::SubjectChanged:
2294             mState.mInitState = InitState::MayNeedInit;
2295             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2296             onStateChange(angle::SubjectMessage::ContentsChanged);
2297 
2298             // Notify siblings that we are dirty.
2299             if (index == rx::kTextureImageImplObserverMessageIndex)
2300             {
2301                 notifySiblings(message);
2302             }
2303             else if (index == kBufferSubjectIndex)
2304             {
2305                 const gl::Buffer *buffer = mState.mBuffer.get();
2306                 ASSERT(buffer != nullptr);
2307 
2308                 // Update cached image desc based on buffer size.
2309                 GLsizeiptr size = GetBoundBufferAvailableSize(mState.mBuffer);
2310 
2311                 ImageDesc desc          = mState.getImageDesc(TextureTarget::Buffer, 0);
2312                 const GLuint pixelBytes = desc.format.info->pixelBytes;
2313                 desc.size.width         = static_cast<GLuint>(size / pixelBytes);
2314 
2315                 mState.setImageDesc(TextureTarget::Buffer, 0, desc);
2316             }
2317             break;
2318         case angle::SubjectMessage::StorageReleased:
2319             // When the TextureStorage is released, it needs to update the
2320             // RenderTargetCache of the Framebuffer attaching this Texture.
2321             // This is currently only for D3D back-end. See http://crbug.com/1234829
2322             if (index == rx::kTextureImageImplObserverMessageIndex)
2323             {
2324                 onStateChange(angle::SubjectMessage::StorageReleased);
2325             }
2326             break;
2327         case angle::SubjectMessage::SubjectMapped:
2328         case angle::SubjectMessage::SubjectUnmapped:
2329         case angle::SubjectMessage::BindingChanged:
2330             ASSERT(index == kBufferSubjectIndex);
2331             break;
2332         case angle::SubjectMessage::InitializationComplete:
2333             ASSERT(index == rx::kTextureImageImplObserverMessageIndex);
2334             setInitState(InitState::Initialized);
2335             break;
2336         case angle::SubjectMessage::InternalMemoryAllocationChanged:
2337             // Need to mark the texture dirty to give the back end a chance to handle the new
2338             // buffer. For example, the Vulkan back end needs to create a new buffer view that
2339             // points to the newly allocated buffer and update the texture descriptor set.
2340             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
2341             break;
2342         default:
2343             UNREACHABLE();
2344             break;
2345     }
2346 }
2347 
getImplementationColorReadFormat(const Context * context) const2348 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
2349 {
2350     return mTexture->getColorReadFormat(context);
2351 }
2352 
getImplementationColorReadType(const Context * context) const2353 GLenum Texture::getImplementationColorReadType(const Context *context) const
2354 {
2355     return mTexture->getColorReadType(context);
2356 }
2357 
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)2358 angle::Result Texture::getTexImage(const Context *context,
2359                                    const PixelPackState &packState,
2360                                    Buffer *packBuffer,
2361                                    TextureTarget target,
2362                                    GLint level,
2363                                    GLenum format,
2364                                    GLenum type,
2365                                    void *pixels)
2366 {
2367     // No-op if the image level is empty.
2368     if (getExtents(target, level).empty())
2369     {
2370         return angle::Result::Continue;
2371     }
2372 
2373     return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
2374                                  pixels);
2375 }
2376 
getCompressedTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,void * pixels)2377 angle::Result Texture::getCompressedTexImage(const Context *context,
2378                                              const PixelPackState &packState,
2379                                              Buffer *packBuffer,
2380                                              TextureTarget target,
2381                                              GLint level,
2382                                              void *pixels)
2383 {
2384     // No-op if the image level is empty.
2385     if (getExtents(target, level).empty())
2386     {
2387         return angle::Result::Continue;
2388     }
2389 
2390     return mTexture->getCompressedTexImage(context, packState, packBuffer, target, level, pixels);
2391 }
2392 
onBindAsImageTexture()2393 void Texture::onBindAsImageTexture()
2394 {
2395     if (!mState.mHasBeenBoundAsImage)
2396     {
2397         mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2398         mState.mHasBeenBoundAsImage = true;
2399     }
2400 }
2401 
2402 }  // namespace gl
2403