• 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 {
IsPointSampled(const SamplerState & samplerState)27 bool IsPointSampled(const SamplerState &samplerState)
28 {
29     return (samplerState.getMagFilter() == GL_NEAREST &&
30             (samplerState.getMinFilter() == GL_NEAREST ||
31              samplerState.getMinFilter() == GL_NEAREST_MIPMAP_NEAREST));
32 }
33 
GetImageDescIndex(TextureTarget target,size_t level)34 size_t GetImageDescIndex(TextureTarget target, size_t level)
35 {
36     return IsCubeMapFaceTarget(target) ? (level * 6 + CubeMapTextureTargetToFaceIndex(target))
37                                        : level;
38 }
39 
DetermineInitState(const Context * context,const uint8_t * pixels)40 InitState DetermineInitState(const Context *context, const uint8_t *pixels)
41 {
42     // Can happen in tests.
43     if (!context || !context->isRobustResourceInitEnabled())
44         return InitState::Initialized;
45 
46     const auto &glState = context->getState();
47     return (pixels == nullptr && glState.getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr)
48                ? InitState::MayNeedInit
49                : InitState::Initialized;
50 }
51 }  // namespace
52 
IsMipmapFiltered(const SamplerState & samplerState)53 bool IsMipmapFiltered(const SamplerState &samplerState)
54 {
55     switch (samplerState.getMinFilter())
56     {
57         case GL_NEAREST:
58         case GL_LINEAR:
59             return false;
60         case GL_NEAREST_MIPMAP_NEAREST:
61         case GL_LINEAR_MIPMAP_NEAREST:
62         case GL_NEAREST_MIPMAP_LINEAR:
63         case GL_LINEAR_MIPMAP_LINEAR:
64             return true;
65         default:
66             UNREACHABLE();
67             return false;
68     }
69 }
70 
SwizzleState()71 SwizzleState::SwizzleState()
72     : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
73 {}
74 
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)75 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
76     : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
77 {}
78 
swizzleRequired() const79 bool SwizzleState::swizzleRequired() const
80 {
81     return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
82            swizzleAlpha != GL_ALPHA;
83 }
84 
operator ==(const SwizzleState & other) const85 bool SwizzleState::operator==(const SwizzleState &other) const
86 {
87     return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
88            swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
89 }
90 
operator !=(const SwizzleState & other) const91 bool SwizzleState::operator!=(const SwizzleState &other) const
92 {
93     return !(*this == other);
94 }
95 
TextureState(TextureType type)96 TextureState::TextureState(TextureType type)
97     : mType(type),
98       mSamplerState(SamplerState::CreateDefaultForTarget(type)),
99       mBaseLevel(0),
100       mMaxLevel(1000),
101       mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
102       mImmutableFormat(false),
103       mImmutableLevels(0),
104       mUsage(GL_NONE),
105       mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
106       mCropRect(0, 0, 0, 0),
107       mGenerateMipmapHint(GL_FALSE),
108       mInitState(InitState::MayNeedInit),
109       mCachedSamplerFormat(SamplerFormat::InvalidEnum),
110       mCachedSamplerCompareMode(GL_NONE),
111       mCachedSamplerFormatValid(false)
112 {}
113 
~TextureState()114 TextureState::~TextureState() {}
115 
swizzleRequired() const116 bool TextureState::swizzleRequired() const
117 {
118     return mSwizzleState.swizzleRequired();
119 }
120 
getEffectiveBaseLevel() const121 GLuint TextureState::getEffectiveBaseLevel() const
122 {
123     if (mImmutableFormat)
124     {
125         // GLES 3.0.4 section 3.8.10
126         return std::min(mBaseLevel, mImmutableLevels - 1);
127     }
128     // Some classes use the effective base level to index arrays with level data. By clamping the
129     // effective base level to max levels these arrays need just one extra item to store properties
130     // that should be returned for all out-of-range base level values, instead of needing special
131     // handling for out-of-range base levels.
132     return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
133 }
134 
getEffectiveMaxLevel() const135 GLuint TextureState::getEffectiveMaxLevel() const
136 {
137     if (mImmutableFormat)
138     {
139         // GLES 3.0.4 section 3.8.10
140         GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
141         clampedMaxLevel        = std::min(clampedMaxLevel, mImmutableLevels - 1);
142         return clampedMaxLevel;
143     }
144     return mMaxLevel;
145 }
146 
getMipmapMaxLevel() const147 GLuint TextureState::getMipmapMaxLevel() const
148 {
149     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
150     GLuint expectedMipLevels       = 0;
151     if (mType == TextureType::_3D)
152     {
153         const int maxDim  = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
154                                     baseImageDesc.size.depth);
155         expectedMipLevels = static_cast<GLuint>(log2(maxDim));
156     }
157     else
158     {
159         expectedMipLevels = static_cast<GLuint>(
160             log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
161     }
162 
163     return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
164 }
165 
setBaseLevel(GLuint baseLevel)166 bool TextureState::setBaseLevel(GLuint baseLevel)
167 {
168     if (mBaseLevel != baseLevel)
169     {
170         mBaseLevel = baseLevel;
171         return true;
172     }
173     return false;
174 }
175 
setMaxLevel(GLuint maxLevel)176 bool TextureState::setMaxLevel(GLuint maxLevel)
177 {
178     if (mMaxLevel != maxLevel)
179     {
180         mMaxLevel = maxLevel;
181         return true;
182     }
183 
184     return false;
185 }
186 
187 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
188 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
189 // per-level checks begin at the base-level.
190 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const191 bool TextureState::isCubeComplete() const
192 {
193     ASSERT(mType == TextureType::CubeMap);
194 
195     angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
196     const ImageDesc &baseImageDesc          = getImageDesc(*face, getEffectiveBaseLevel());
197     if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
198     {
199         return false;
200     }
201 
202     ++face;
203 
204     for (; face != kAfterCubeMapTextureTargetMax; ++face)
205     {
206         const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
207         if (faceImageDesc.size.width != baseImageDesc.size.width ||
208             faceImageDesc.size.height != baseImageDesc.size.height ||
209             !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
210         {
211             return false;
212         }
213     }
214 
215     return true;
216 }
217 
getBaseLevelDesc() const218 const ImageDesc &TextureState::getBaseLevelDesc() const
219 {
220     ASSERT(mType != TextureType::CubeMap || isCubeComplete());
221     return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
222 }
223 
setCrop(const gl::Rectangle & rect)224 void TextureState::setCrop(const gl::Rectangle &rect)
225 {
226     mCropRect = rect;
227 }
228 
getCrop() const229 const gl::Rectangle &TextureState::getCrop() const
230 {
231     return mCropRect;
232 }
233 
setGenerateMipmapHint(GLenum hint)234 void TextureState::setGenerateMipmapHint(GLenum hint)
235 {
236     mGenerateMipmapHint = hint;
237 }
238 
getGenerateMipmapHint() const239 GLenum TextureState::getGenerateMipmapHint() const
240 {
241     return mGenerateMipmapHint;
242 }
243 
computeRequiredSamplerFormat(const SamplerState & samplerState) const244 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
245 {
246     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
247     if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT ||
248          baseImageDesc.format.info->format == GL_DEPTH_STENCIL) &&
249         samplerState.getCompareMode() != GL_NONE)
250     {
251         return SamplerFormat::Shadow;
252     }
253     else
254     {
255         switch (baseImageDesc.format.info->componentType)
256         {
257             case GL_UNSIGNED_NORMALIZED:
258             case GL_SIGNED_NORMALIZED:
259             case GL_FLOAT:
260                 return SamplerFormat::Float;
261             case GL_INT:
262                 return SamplerFormat::Signed;
263             case GL_UNSIGNED_INT:
264                 return SamplerFormat::Unsigned;
265             default:
266                 return SamplerFormat::InvalidEnum;
267         }
268     }
269 }
270 
computeSamplerCompleteness(const SamplerState & samplerState,const State & data) const271 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
272                                               const State &data) const
273 {
274     if (mBaseLevel > mMaxLevel)
275     {
276         return false;
277     }
278     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
279     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
280         baseImageDesc.size.depth == 0)
281     {
282         return false;
283     }
284     // The cases where the texture is incomplete because base level is out of range should be
285     // handled by the above condition.
286     ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
287 
288     if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
289     {
290         return false;
291     }
292 
293     // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
294     // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
295     // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
296     // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
297     // incomplete texture. So, we ignore filtering for multisample texture completeness here.
298     if (!IsMultisampled(mType) &&
299         !baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) &&
300         !IsPointSampled(samplerState))
301     {
302         return false;
303     }
304     bool npotSupport = data.getExtensions().textureNPOT || data.getClientMajorVersion() >= 3;
305     if (!npotSupport)
306     {
307         if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
308              samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
309             (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
310              samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
311         {
312             return false;
313         }
314     }
315 
316     if (mType != TextureType::_2DMultisample && IsMipmapFiltered(samplerState))
317     {
318         if (!npotSupport)
319         {
320             if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
321             {
322                 return false;
323             }
324         }
325 
326         if (!computeMipmapCompleteness())
327         {
328             return false;
329         }
330     }
331     else
332     {
333         if (mType == TextureType::CubeMap && !isCubeComplete())
334         {
335             return false;
336         }
337     }
338 
339     // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
340     // texture unit that would have been rejected by a call to TexParameter* for the texture bound
341     // to that unit, the behavior of the implementation is as if the texture were incomplete. For
342     // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
343     // sampler object bound to a texture unit and the texture bound to that unit is an external
344     // texture, the texture will be considered incomplete.
345     // Sampler object state which does not affect sampling for the type of texture bound to a
346     // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness.
347     if (mType == TextureType::External)
348     {
349         if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
350             samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
351         {
352             return false;
353         }
354 
355         if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
356         {
357             return false;
358         }
359     }
360 
361     // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
362     // The internalformat specified for the texture arrays is a sized internal depth or
363     // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
364     // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
365     // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
366     if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
367         data.getClientMajorVersion() >= 3)
368     {
369         // Note: we restrict this validation to sized types. For the OES_depth_textures
370         // extension, due to some underspecification problems, we must allow linear filtering
371         // for legacy compatibility with WebGL 1.
372         // See http://crbug.com/649200
373         if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
374         {
375             if ((samplerState.getMinFilter() != GL_NEAREST &&
376                  samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
377                 samplerState.getMagFilter() != GL_NEAREST)
378             {
379                 return false;
380             }
381         }
382     }
383 
384     // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
385     // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
386     // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
387     // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
388     // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
389     // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
390     // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
391     // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
392     // texture completeness here.
393     if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
394         mDepthStencilTextureMode == GL_STENCIL_INDEX)
395     {
396         if ((samplerState.getMinFilter() != GL_NEAREST &&
397              samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
398             samplerState.getMagFilter() != GL_NEAREST)
399         {
400             return false;
401         }
402     }
403 
404     return true;
405 }
406 
computeMipmapCompleteness() const407 bool TextureState::computeMipmapCompleteness() const
408 {
409     const GLuint maxLevel = getMipmapMaxLevel();
410 
411     for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
412     {
413         if (mType == TextureType::CubeMap)
414         {
415             for (TextureTarget face : AllCubeFaceTextureTargets())
416             {
417                 if (!computeLevelCompleteness(face, level))
418                 {
419                     return false;
420                 }
421             }
422         }
423         else
424         {
425             if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
426             {
427                 return false;
428             }
429         }
430     }
431 
432     return true;
433 }
434 
computeLevelCompleteness(TextureTarget target,size_t level) const435 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
436 {
437     ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
438 
439     if (mImmutableFormat)
440     {
441         return true;
442     }
443 
444     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
445     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
446         baseImageDesc.size.depth == 0)
447     {
448         return false;
449     }
450 
451     const ImageDesc &levelImageDesc = getImageDesc(target, level);
452     if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
453         levelImageDesc.size.depth == 0)
454     {
455         return false;
456     }
457 
458     if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
459     {
460         return false;
461     }
462 
463     ASSERT(level >= getEffectiveBaseLevel());
464     const size_t relativeLevel = level - getEffectiveBaseLevel();
465     if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
466     {
467         return false;
468     }
469 
470     if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
471     {
472         return false;
473     }
474 
475     if (mType == TextureType::_3D)
476     {
477         if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
478         {
479             return false;
480         }
481     }
482     else if (mType == TextureType::_2DArray)
483     {
484         if (levelImageDesc.size.depth != baseImageDesc.size.depth)
485         {
486             return false;
487         }
488     }
489 
490     return true;
491 }
492 
getBaseImageTarget() const493 TextureTarget TextureState::getBaseImageTarget() const
494 {
495     return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
496                                          : NonCubeTextureTypeToTarget(mType);
497 }
498 
ImageDesc()499 ImageDesc::ImageDesc()
500     : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
501 {}
502 
ImageDesc(const Extents & size,const Format & format,const InitState initState)503 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
504     : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
505 {}
506 
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)507 ImageDesc::ImageDesc(const Extents &size,
508                      const Format &format,
509                      const GLsizei samples,
510                      const bool fixedSampleLocations,
511                      const InitState initState)
512     : size(size),
513       format(format),
514       samples(samples),
515       fixedSampleLocations(fixedSampleLocations),
516       initState(initState)
517 {}
518 
getMemorySize() const519 GLint ImageDesc::getMemorySize() const
520 {
521     // Assume allocated size is around width * height * depth * samples * pixelBytes
522     angle::CheckedNumeric<GLint> levelSize = 1;
523     levelSize *= format.info->pixelBytes;
524     levelSize *= size.width;
525     levelSize *= size.height;
526     levelSize *= size.depth;
527     levelSize *= std::max(samples, 1);
528     return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
529 }
530 
getImageDesc(TextureTarget target,size_t level) const531 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
532 {
533     size_t descIndex = GetImageDescIndex(target, level);
534     ASSERT(descIndex < mImageDescs.size());
535     return mImageDescs[descIndex];
536 }
537 
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)538 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
539 {
540     size_t descIndex = GetImageDescIndex(target, level);
541     ASSERT(descIndex < mImageDescs.size());
542     mImageDescs[descIndex] = desc;
543     if (desc.initState == InitState::MayNeedInit)
544     {
545         mInitState = InitState::MayNeedInit;
546     }
547 }
548 
549 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
550 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
551 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const552 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
553 {
554     if (imageIndex.isEntireLevelCubeMap())
555     {
556         ASSERT(isCubeComplete());
557         const GLint levelIndex = imageIndex.getLevelIndex();
558         return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
559     }
560 
561     return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
562 }
563 
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)564 void TextureState::setImageDescChain(GLuint baseLevel,
565                                      GLuint maxLevel,
566                                      Extents baseSize,
567                                      const Format &format,
568                                      InitState initState)
569 {
570     for (GLuint level = baseLevel; level <= maxLevel; level++)
571     {
572         int relativeLevel = (level - baseLevel);
573         Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
574                           std::max<int>(baseSize.height >> relativeLevel, 1),
575                           (mType == TextureType::_2DArray)
576                               ? baseSize.depth
577                               : std::max<int>(baseSize.depth >> relativeLevel, 1));
578         ImageDesc levelInfo(levelSize, format, initState);
579 
580         if (mType == TextureType::CubeMap)
581         {
582             for (TextureTarget face : AllCubeFaceTextureTargets())
583             {
584                 setImageDesc(face, level, levelInfo);
585             }
586         }
587         else
588         {
589             setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
590         }
591     }
592 }
593 
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)594 void TextureState::setImageDescChainMultisample(Extents baseSize,
595                                                 const Format &format,
596                                                 GLsizei samples,
597                                                 bool fixedSampleLocations,
598                                                 InitState initState)
599 {
600     ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
601     ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
602     setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
603 }
604 
clearImageDesc(TextureTarget target,size_t level)605 void TextureState::clearImageDesc(TextureTarget target, size_t level)
606 {
607     setImageDesc(target, level, ImageDesc());
608 }
609 
clearImageDescs()610 void TextureState::clearImageDescs()
611 {
612     for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
613     {
614         mImageDescs[descIndex] = ImageDesc();
615     }
616 }
617 
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)618 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
619     : RefCountObject(id.value),
620       mState(type),
621       mTexture(factory->createTexture(mState)),
622       mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
623       mLabel(),
624       mBoundSurface(nullptr),
625       mBoundStream(nullptr)
626 {
627     mImplObserver.bind(mTexture);
628 
629     // Initially assume the implementation is dirty.
630     mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
631 }
632 
onDestroy(const Context * context)633 void Texture::onDestroy(const Context *context)
634 {
635     if (mBoundSurface)
636     {
637         ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
638         mBoundSurface = nullptr;
639     }
640     if (mBoundStream)
641     {
642         mBoundStream->releaseTextures();
643         mBoundStream = nullptr;
644     }
645 
646     (void)(orphanImages(context));
647 
648     if (mTexture)
649     {
650         mTexture->onDestroy(context);
651     }
652 }
653 
~Texture()654 Texture::~Texture()
655 {
656     SafeDelete(mTexture);
657 }
658 
setLabel(const Context * context,const std::string & label)659 void Texture::setLabel(const Context *context, const std::string &label)
660 {
661     mLabel = label;
662     signalDirtyState(DIRTY_BIT_LABEL);
663 }
664 
getLabel() const665 const std::string &Texture::getLabel() const
666 {
667     return mLabel;
668 }
669 
setSwizzleRed(const Context * context,GLenum swizzleRed)670 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
671 {
672     mState.mSwizzleState.swizzleRed = swizzleRed;
673     signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
674 }
675 
getSwizzleRed() const676 GLenum Texture::getSwizzleRed() const
677 {
678     return mState.mSwizzleState.swizzleRed;
679 }
680 
setSwizzleGreen(const Context * context,GLenum swizzleGreen)681 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
682 {
683     mState.mSwizzleState.swizzleGreen = swizzleGreen;
684     signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
685 }
686 
getSwizzleGreen() const687 GLenum Texture::getSwizzleGreen() const
688 {
689     return mState.mSwizzleState.swizzleGreen;
690 }
691 
setSwizzleBlue(const Context * context,GLenum swizzleBlue)692 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
693 {
694     mState.mSwizzleState.swizzleBlue = swizzleBlue;
695     signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
696 }
697 
getSwizzleBlue() const698 GLenum Texture::getSwizzleBlue() const
699 {
700     return mState.mSwizzleState.swizzleBlue;
701 }
702 
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)703 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
704 {
705     mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
706     signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
707 }
708 
getSwizzleAlpha() const709 GLenum Texture::getSwizzleAlpha() const
710 {
711     return mState.mSwizzleState.swizzleAlpha;
712 }
713 
setMinFilter(const Context * context,GLenum minFilter)714 void Texture::setMinFilter(const Context *context, GLenum minFilter)
715 {
716     mState.mSamplerState.setMinFilter(minFilter);
717     signalDirtyState(DIRTY_BIT_MIN_FILTER);
718 }
719 
getMinFilter() const720 GLenum Texture::getMinFilter() const
721 {
722     return mState.mSamplerState.getMinFilter();
723 }
724 
setMagFilter(const Context * context,GLenum magFilter)725 void Texture::setMagFilter(const Context *context, GLenum magFilter)
726 {
727     mState.mSamplerState.setMagFilter(magFilter);
728     signalDirtyState(DIRTY_BIT_MAG_FILTER);
729 }
730 
getMagFilter() const731 GLenum Texture::getMagFilter() const
732 {
733     return mState.mSamplerState.getMagFilter();
734 }
735 
setWrapS(const Context * context,GLenum wrapS)736 void Texture::setWrapS(const Context *context, GLenum wrapS)
737 {
738     mState.mSamplerState.setWrapS(wrapS);
739     signalDirtyState(DIRTY_BIT_WRAP_S);
740 }
741 
getWrapS() const742 GLenum Texture::getWrapS() const
743 {
744     return mState.mSamplerState.getWrapS();
745 }
746 
setWrapT(const Context * context,GLenum wrapT)747 void Texture::setWrapT(const Context *context, GLenum wrapT)
748 {
749     mState.mSamplerState.setWrapT(wrapT);
750     signalDirtyState(DIRTY_BIT_WRAP_T);
751 }
752 
getWrapT() const753 GLenum Texture::getWrapT() const
754 {
755     return mState.mSamplerState.getWrapT();
756 }
757 
setWrapR(const Context * context,GLenum wrapR)758 void Texture::setWrapR(const Context *context, GLenum wrapR)
759 {
760     mState.mSamplerState.setWrapR(wrapR);
761     signalDirtyState(DIRTY_BIT_WRAP_R);
762 }
763 
getWrapR() const764 GLenum Texture::getWrapR() const
765 {
766     return mState.mSamplerState.getWrapR();
767 }
768 
setMaxAnisotropy(const Context * context,float maxAnisotropy)769 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
770 {
771     mState.mSamplerState.setMaxAnisotropy(maxAnisotropy);
772     signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
773 }
774 
getMaxAnisotropy() const775 float Texture::getMaxAnisotropy() const
776 {
777     return mState.mSamplerState.getMaxAnisotropy();
778 }
779 
setMinLod(const Context * context,GLfloat minLod)780 void Texture::setMinLod(const Context *context, GLfloat minLod)
781 {
782     mState.mSamplerState.setMinLod(minLod);
783     signalDirtyState(DIRTY_BIT_MIN_LOD);
784 }
785 
getMinLod() const786 GLfloat Texture::getMinLod() const
787 {
788     return mState.mSamplerState.getMinLod();
789 }
790 
setMaxLod(const Context * context,GLfloat maxLod)791 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
792 {
793     mState.mSamplerState.setMaxLod(maxLod);
794     signalDirtyState(DIRTY_BIT_MAX_LOD);
795 }
796 
getMaxLod() const797 GLfloat Texture::getMaxLod() const
798 {
799     return mState.mSamplerState.getMaxLod();
800 }
801 
setCompareMode(const Context * context,GLenum compareMode)802 void Texture::setCompareMode(const Context *context, GLenum compareMode)
803 {
804     mState.mSamplerState.setCompareMode(compareMode);
805     signalDirtyState(DIRTY_BIT_COMPARE_MODE);
806 }
807 
getCompareMode() const808 GLenum Texture::getCompareMode() const
809 {
810     return mState.mSamplerState.getCompareMode();
811 }
812 
setCompareFunc(const Context * context,GLenum compareFunc)813 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
814 {
815     mState.mSamplerState.setCompareFunc(compareFunc);
816     signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
817 }
818 
getCompareFunc() const819 GLenum Texture::getCompareFunc() const
820 {
821     return mState.mSamplerState.getCompareFunc();
822 }
823 
setSRGBDecode(const Context * context,GLenum sRGBDecode)824 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
825 {
826     mState.mSamplerState.setSRGBDecode(sRGBDecode);
827     signalDirtyState(DIRTY_BIT_SRGB_DECODE);
828 }
829 
getSRGBDecode() const830 GLenum Texture::getSRGBDecode() const
831 {
832     return mState.mSamplerState.getSRGBDecode();
833 }
834 
getSamplerState() const835 const SamplerState &Texture::getSamplerState() const
836 {
837     return mState.mSamplerState;
838 }
839 
setBaseLevel(const Context * context,GLuint baseLevel)840 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
841 {
842     if (mState.setBaseLevel(baseLevel))
843     {
844         ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
845         signalDirtyState(DIRTY_BIT_BASE_LEVEL);
846     }
847 
848     return angle::Result::Continue;
849 }
850 
getBaseLevel() const851 GLuint Texture::getBaseLevel() const
852 {
853     return mState.mBaseLevel;
854 }
855 
setMaxLevel(const Context * context,GLuint maxLevel)856 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
857 {
858     if (mState.setMaxLevel(maxLevel))
859     {
860         signalDirtyState(DIRTY_BIT_MAX_LEVEL);
861     }
862 }
863 
getMaxLevel() const864 GLuint Texture::getMaxLevel() const
865 {
866     return mState.mMaxLevel;
867 }
868 
setDepthStencilTextureMode(const Context * context,GLenum mode)869 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
870 {
871     if (mState.mDepthStencilTextureMode != mode)
872     {
873         mState.mDepthStencilTextureMode = mode;
874         signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
875     }
876 }
877 
getDepthStencilTextureMode() const878 GLenum Texture::getDepthStencilTextureMode() const
879 {
880     return mState.mDepthStencilTextureMode;
881 }
882 
getImmutableFormat() const883 bool Texture::getImmutableFormat() const
884 {
885     return mState.mImmutableFormat;
886 }
887 
getImmutableLevels() const888 GLuint Texture::getImmutableLevels() const
889 {
890     return mState.mImmutableLevels;
891 }
892 
setUsage(const Context * context,GLenum usage)893 void Texture::setUsage(const Context *context, GLenum usage)
894 {
895     mState.mUsage = usage;
896     signalDirtyState(DIRTY_BIT_USAGE);
897 }
898 
getUsage() const899 GLenum Texture::getUsage() const
900 {
901     return mState.mUsage;
902 }
903 
getTextureState() const904 const TextureState &Texture::getTextureState() const
905 {
906     return mState;
907 }
908 
getWidth(TextureTarget target,size_t level) const909 size_t Texture::getWidth(TextureTarget target, size_t level) const
910 {
911     ASSERT(TextureTargetToType(target) == mState.mType);
912     return mState.getImageDesc(target, level).size.width;
913 }
914 
getHeight(TextureTarget target,size_t level) const915 size_t Texture::getHeight(TextureTarget target, size_t level) const
916 {
917     ASSERT(TextureTargetToType(target) == mState.mType);
918     return mState.getImageDesc(target, level).size.height;
919 }
920 
getDepth(TextureTarget target,size_t level) const921 size_t Texture::getDepth(TextureTarget target, size_t level) const
922 {
923     ASSERT(TextureTargetToType(target) == mState.mType);
924     return mState.getImageDesc(target, level).size.depth;
925 }
926 
getFormat(TextureTarget target,size_t level) const927 const Format &Texture::getFormat(TextureTarget target, size_t level) const
928 {
929     ASSERT(TextureTargetToType(target) == mState.mType);
930     return mState.getImageDesc(target, level).format;
931 }
932 
getSamples(TextureTarget target,size_t level) const933 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
934 {
935     ASSERT(TextureTargetToType(target) == mState.mType);
936     return mState.getImageDesc(target, level).samples;
937 }
938 
getFixedSampleLocations(TextureTarget target,size_t level) const939 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
940 {
941     ASSERT(TextureTargetToType(target) == mState.mType);
942     return mState.getImageDesc(target, level).fixedSampleLocations;
943 }
944 
getMipmapMaxLevel() const945 GLuint Texture::getMipmapMaxLevel() const
946 {
947     return mState.getMipmapMaxLevel();
948 }
949 
isMipmapComplete() const950 bool Texture::isMipmapComplete() const
951 {
952     return mState.computeMipmapCompleteness();
953 }
954 
getBoundSurface() const955 egl::Surface *Texture::getBoundSurface() const
956 {
957     return mBoundSurface;
958 }
959 
getBoundStream() const960 egl::Stream *Texture::getBoundStream() const
961 {
962     return mBoundStream;
963 }
964 
getMemorySize() const965 GLint Texture::getMemorySize() const
966 {
967     GLint implSize = mTexture->getMemorySize();
968     if (implSize > 0)
969     {
970         return implSize;
971     }
972 
973     angle::CheckedNumeric<GLint> size = 0;
974     for (const ImageDesc &imageDesc : mState.mImageDescs)
975     {
976         size += imageDesc.getMemorySize();
977     }
978     return size.ValueOrDefault(std::numeric_limits<GLint>::max());
979 }
980 
getLevelMemorySize(TextureTarget target,GLint level) const981 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
982 {
983     GLint implSize = mTexture->getLevelMemorySize(target, level);
984     if (implSize > 0)
985     {
986         return implSize;
987     }
988 
989     return mState.getImageDesc(target, level).getMemorySize();
990 }
991 
signalDirtyStorage(InitState initState)992 void Texture::signalDirtyStorage(InitState initState)
993 {
994     mState.mInitState = initState;
995     invalidateCompletenessCache();
996     mState.mCachedSamplerFormatValid = false;
997     onStateChange(angle::SubjectMessage::SubjectChanged);
998 }
999 
signalDirtyState(size_t dirtyBit)1000 void Texture::signalDirtyState(size_t dirtyBit)
1001 {
1002     mDirtyBits.set(dirtyBit);
1003     invalidateCompletenessCache();
1004     mState.mCachedSamplerFormatValid = false;
1005     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1006 }
1007 
setImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type,const uint8_t * pixels)1008 angle::Result Texture::setImage(Context *context,
1009                                 const PixelUnpackState &unpackState,
1010                                 TextureTarget target,
1011                                 GLint level,
1012                                 GLenum internalFormat,
1013                                 const Extents &size,
1014                                 GLenum format,
1015                                 GLenum type,
1016                                 const uint8_t *pixels)
1017 {
1018     ASSERT(TextureTargetToType(target) == mState.mType);
1019 
1020     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1021     ANGLE_TRY(releaseTexImageInternal(context));
1022     ANGLE_TRY(orphanImages(context));
1023 
1024     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1025 
1026     ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1027                                  pixels));
1028 
1029     InitState initState = DetermineInitState(context, pixels);
1030     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1031 
1032     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1033 
1034     signalDirtyStorage(initState);
1035 
1036     return angle::Result::Continue;
1037 }
1038 
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1039 angle::Result Texture::setSubImage(Context *context,
1040                                    const PixelUnpackState &unpackState,
1041                                    Buffer *unpackBuffer,
1042                                    TextureTarget target,
1043                                    GLint level,
1044                                    const Box &area,
1045                                    GLenum format,
1046                                    GLenum type,
1047                                    const uint8_t *pixels)
1048 {
1049     ASSERT(TextureTargetToType(target) == mState.mType);
1050 
1051     ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
1052 
1053     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1054 
1055     ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1056                                     pixels));
1057 
1058     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1059 
1060     onStateChange(angle::SubjectMessage::ContentsChanged);
1061 
1062     return angle::Result::Continue;
1063 }
1064 
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1065 angle::Result Texture::setCompressedImage(Context *context,
1066                                           const PixelUnpackState &unpackState,
1067                                           TextureTarget target,
1068                                           GLint level,
1069                                           GLenum internalFormat,
1070                                           const Extents &size,
1071                                           size_t imageSize,
1072                                           const uint8_t *pixels)
1073 {
1074     ASSERT(TextureTargetToType(target) == mState.mType);
1075 
1076     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1077     ANGLE_TRY(releaseTexImageInternal(context));
1078     ANGLE_TRY(orphanImages(context));
1079 
1080     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1081 
1082     ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1083                                            imageSize, pixels));
1084 
1085     InitState initState = DetermineInitState(context, pixels);
1086     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1087     signalDirtyStorage(initState);
1088 
1089     return angle::Result::Continue;
1090 }
1091 
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1092 angle::Result Texture::setCompressedSubImage(const Context *context,
1093                                              const PixelUnpackState &unpackState,
1094                                              TextureTarget target,
1095                                              GLint level,
1096                                              const Box &area,
1097                                              GLenum format,
1098                                              size_t imageSize,
1099                                              const uint8_t *pixels)
1100 {
1101     ASSERT(TextureTargetToType(target) == mState.mType);
1102 
1103     ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
1104 
1105     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1106 
1107     ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1108                                               pixels));
1109 
1110     onStateChange(angle::SubjectMessage::ContentsChanged);
1111 
1112     return angle::Result::Continue;
1113 }
1114 
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1115 angle::Result Texture::copyImage(Context *context,
1116                                  TextureTarget target,
1117                                  GLint level,
1118                                  const Rectangle &sourceArea,
1119                                  GLenum internalFormat,
1120                                  Framebuffer *source)
1121 {
1122     ASSERT(TextureTargetToType(target) == mState.mType);
1123 
1124     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1125     ANGLE_TRY(releaseTexImageInternal(context));
1126     ANGLE_TRY(orphanImages(context));
1127 
1128     // Use the source FBO size as the init image area.
1129     Box destBox(0, 0, 0, sourceArea.width, sourceArea.height, 1);
1130     ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1131 
1132     ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1133 
1134     ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1135 
1136     const InternalFormat &internalFormatInfo =
1137         GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1138 
1139     mState.setImageDesc(target, level,
1140                         ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
1141                                   Format(internalFormatInfo), InitState::Initialized));
1142 
1143     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1144 
1145     // We need to initialize this texture only if the source attachment is not initialized.
1146     signalDirtyStorage(InitState::Initialized);
1147 
1148     return angle::Result::Continue;
1149 }
1150 
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1151 angle::Result Texture::copySubImage(Context *context,
1152                                     const ImageIndex &index,
1153                                     const Offset &destOffset,
1154                                     const Rectangle &sourceArea,
1155                                     Framebuffer *source)
1156 {
1157     ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1158 
1159     Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceArea.width, sourceArea.height, 1);
1160     ANGLE_TRY(
1161         ensureSubImageInitialized(context, index.getTarget(), index.getLevelIndex(), destBox));
1162 
1163     ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1164     ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1165 
1166     onStateChange(angle::SubjectMessage::ContentsChanged);
1167 
1168     return angle::Result::Continue;
1169 }
1170 
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1171 angle::Result Texture::copyTexture(Context *context,
1172                                    TextureTarget target,
1173                                    GLint level,
1174                                    GLenum internalFormat,
1175                                    GLenum type,
1176                                    GLint sourceLevel,
1177                                    bool unpackFlipY,
1178                                    bool unpackPremultiplyAlpha,
1179                                    bool unpackUnmultiplyAlpha,
1180                                    Texture *source)
1181 {
1182     ASSERT(TextureTargetToType(target) == mState.mType);
1183     ASSERT(source->getType() != TextureType::CubeMap);
1184 
1185     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1186     ANGLE_TRY(releaseTexImageInternal(context));
1187     ANGLE_TRY(orphanImages(context));
1188 
1189     // Initialize source texture.
1190     // Note: we don't have a way to notify which portions of the image changed currently.
1191     ANGLE_TRY(source->ensureInitialized(context));
1192 
1193     ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1194 
1195     ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1196                                     unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1197 
1198     const auto &sourceDesc =
1199         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1200     const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1201     mState.setImageDesc(
1202         target, level,
1203         ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1204 
1205     signalDirtyStorage(InitState::Initialized);
1206 
1207     return angle::Result::Continue;
1208 }
1209 
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1210 angle::Result Texture::copySubTexture(const Context *context,
1211                                       TextureTarget target,
1212                                       GLint level,
1213                                       const Offset &destOffset,
1214                                       GLint sourceLevel,
1215                                       const Box &sourceBox,
1216                                       bool unpackFlipY,
1217                                       bool unpackPremultiplyAlpha,
1218                                       bool unpackUnmultiplyAlpha,
1219                                       Texture *source)
1220 {
1221     ASSERT(TextureTargetToType(target) == mState.mType);
1222 
1223     // Ensure source is initialized.
1224     ANGLE_TRY(source->ensureInitialized(context));
1225 
1226     Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1227                 sourceBox.depth);
1228     ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1229 
1230     ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1231 
1232     ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1233                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1234                                        source));
1235 
1236     onStateChange(angle::SubjectMessage::ContentsChanged);
1237 
1238     return angle::Result::Continue;
1239 }
1240 
copyCompressedTexture(Context * context,const Texture * source)1241 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1242 {
1243     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1244     ANGLE_TRY(releaseTexImageInternal(context));
1245     ANGLE_TRY(orphanImages(context));
1246 
1247     ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1248 
1249     ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1250     const auto &sourceDesc =
1251         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1252     mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1253 
1254     return angle::Result::Continue;
1255 }
1256 
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1257 angle::Result Texture::setStorage(Context *context,
1258                                   TextureType type,
1259                                   GLsizei levels,
1260                                   GLenum internalFormat,
1261                                   const Extents &size)
1262 {
1263     ASSERT(type == mState.mType);
1264 
1265     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1266     ANGLE_TRY(releaseTexImageInternal(context));
1267     ANGLE_TRY(orphanImages(context));
1268 
1269     ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1270 
1271     mState.mImmutableFormat = true;
1272     mState.mImmutableLevels = static_cast<GLuint>(levels);
1273     mState.clearImageDescs();
1274     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1275                              InitState::MayNeedInit);
1276 
1277     // Changing the texture to immutable can trigger a change in the base and max levels:
1278     // GLES 3.0.4 section 3.8.10 pg 158:
1279     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1280     // clamped to the range[levelbase;levels].
1281     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1282     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1283 
1284     signalDirtyStorage(InitState::MayNeedInit);
1285 
1286     return angle::Result::Continue;
1287 }
1288 
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1289 angle::Result Texture::setImageExternal(Context *context,
1290                                         TextureTarget target,
1291                                         GLint level,
1292                                         GLenum internalFormat,
1293                                         const Extents &size,
1294                                         GLenum format,
1295                                         GLenum type)
1296 {
1297     ASSERT(TextureTargetToType(target) == mState.mType);
1298 
1299     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1300     ANGLE_TRY(releaseTexImageInternal(context));
1301     ANGLE_TRY(orphanImages(context));
1302 
1303     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1304 
1305     ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1306 
1307     InitState initState = InitState::Initialized;
1308     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1309 
1310     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1311 
1312     signalDirtyStorage(initState);
1313 
1314     return angle::Result::Continue;
1315 }
1316 
setStorageMultisample(Context * context,TextureType type,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1317 angle::Result Texture::setStorageMultisample(Context *context,
1318                                              TextureType type,
1319                                              GLsizei samples,
1320                                              GLint internalFormat,
1321                                              const Extents &size,
1322                                              bool fixedSampleLocations)
1323 {
1324     ASSERT(type == mState.mType);
1325 
1326     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1327     ANGLE_TRY(releaseTexImageInternal(context));
1328     ANGLE_TRY(orphanImages(context));
1329 
1330     ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1331                                               fixedSampleLocations));
1332 
1333     mState.mImmutableFormat = true;
1334     mState.mImmutableLevels = static_cast<GLuint>(1);
1335     mState.clearImageDescs();
1336     mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1337                                         InitState::MayNeedInit);
1338 
1339     signalDirtyStorage(InitState::MayNeedInit);
1340 
1341     return angle::Result::Continue;
1342 }
1343 
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset)1344 angle::Result Texture::setStorageExternalMemory(Context *context,
1345                                                 TextureType type,
1346                                                 GLsizei levels,
1347                                                 GLenum internalFormat,
1348                                                 const Extents &size,
1349                                                 MemoryObject *memoryObject,
1350                                                 GLuint64 offset)
1351 {
1352     ASSERT(type == mState.mType);
1353 
1354     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1355     ANGLE_TRY(releaseTexImageInternal(context));
1356     ANGLE_TRY(orphanImages(context));
1357 
1358     ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1359                                                  memoryObject, offset));
1360 
1361     mState.mImmutableFormat = true;
1362     mState.mImmutableLevels = static_cast<GLuint>(levels);
1363     mState.clearImageDescs();
1364     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1365                              InitState::MayNeedInit);
1366 
1367     // Changing the texture to immutable can trigger a change in the base and max levels:
1368     // GLES 3.0.4 section 3.8.10 pg 158:
1369     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1370     // clamped to the range[levelbase;levels].
1371     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1372     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1373 
1374     signalDirtyStorage(InitState::Initialized);
1375 
1376     return angle::Result::Continue;
1377 }
1378 
generateMipmap(Context * context)1379 angle::Result Texture::generateMipmap(Context *context)
1380 {
1381     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1382     ANGLE_TRY(releaseTexImageInternal(context));
1383 
1384     // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1385     // is not mip complete.
1386     if (!isMipmapComplete())
1387     {
1388         ANGLE_TRY(orphanImages(context));
1389     }
1390 
1391     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1392     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1393 
1394     if (maxLevel <= baseLevel)
1395     {
1396         return angle::Result::Continue;
1397     }
1398 
1399     if (hasAnyDirtyBit())
1400     {
1401         ANGLE_TRY(syncState(context));
1402     }
1403 
1404     // Clear the base image(s) immediately if needed
1405     if (context->isRobustResourceInitEnabled())
1406     {
1407         ImageIndexIterator it =
1408             ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1409                                             ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1410         while (it.hasNext())
1411         {
1412             const ImageIndex index = it.next();
1413             const ImageDesc &desc  = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1414 
1415             if (desc.initState == InitState::MayNeedInit)
1416             {
1417                 ANGLE_TRY(initializeContents(context, index));
1418             }
1419         }
1420     }
1421 
1422     ANGLE_TRY(mTexture->generateMipmap(context));
1423 
1424     // Propagate the format and size of the bsae mip to the smaller ones. Cube maps are guaranteed
1425     // to have faces of the same size and format so any faces can be picked.
1426     const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1427     mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1428                              InitState::Initialized);
1429 
1430     signalDirtyStorage(InitState::Initialized);
1431 
1432     return angle::Result::Continue;
1433 }
1434 
bindTexImageFromSurface(Context * context,egl::Surface * surface)1435 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1436 {
1437     ASSERT(surface);
1438 
1439     if (mBoundSurface)
1440     {
1441         ANGLE_TRY(releaseTexImageFromSurface(context));
1442     }
1443 
1444     ANGLE_TRY(mTexture->bindTexImage(context, surface));
1445     mBoundSurface = surface;
1446 
1447     // Set the image info to the size and format of the surface
1448     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1449     Extents size(surface->getWidth(), surface->getHeight(), 1);
1450     ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1451     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1452     signalDirtyStorage(InitState::Initialized);
1453     return angle::Result::Continue;
1454 }
1455 
releaseTexImageFromSurface(const Context * context)1456 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1457 {
1458     ASSERT(mBoundSurface);
1459     mBoundSurface = nullptr;
1460     ANGLE_TRY(mTexture->releaseTexImage(context));
1461 
1462     // Erase the image info for level 0
1463     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1464     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1465     signalDirtyStorage(InitState::Initialized);
1466     return angle::Result::Continue;
1467 }
1468 
bindStream(egl::Stream * stream)1469 void Texture::bindStream(egl::Stream *stream)
1470 {
1471     ASSERT(stream);
1472 
1473     // It should not be possible to bind a texture already bound to another stream
1474     ASSERT(mBoundStream == nullptr);
1475 
1476     mBoundStream = stream;
1477 
1478     ASSERT(mState.mType == TextureType::External);
1479 }
1480 
releaseStream()1481 void Texture::releaseStream()
1482 {
1483     ASSERT(mBoundStream);
1484     mBoundStream = nullptr;
1485 }
1486 
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1487 angle::Result Texture::acquireImageFromStream(const Context *context,
1488                                               const egl::Stream::GLTextureDescription &desc)
1489 {
1490     ASSERT(mBoundStream != nullptr);
1491     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1492 
1493     Extents size(desc.width, desc.height, 1);
1494     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1495                         ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1496     signalDirtyStorage(InitState::Initialized);
1497     return angle::Result::Continue;
1498 }
1499 
releaseImageFromStream(const Context * context)1500 angle::Result Texture::releaseImageFromStream(const Context *context)
1501 {
1502     ASSERT(mBoundStream != nullptr);
1503     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1504                                          egl::Stream::GLTextureDescription()));
1505 
1506     // Set to incomplete
1507     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1508     signalDirtyStorage(InitState::Initialized);
1509     return angle::Result::Continue;
1510 }
1511 
releaseTexImageInternal(Context * context)1512 angle::Result Texture::releaseTexImageInternal(Context *context)
1513 {
1514     if (mBoundSurface)
1515     {
1516         // Notify the surface
1517         egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1518         // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1519         if (eglErr.isError())
1520         {
1521             context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1522                                  __FILE__, ANGLE_FUNCTION, __LINE__);
1523         }
1524 
1525         // Then, call the same method as from the surface
1526         ANGLE_TRY(releaseTexImageFromSurface(context));
1527     }
1528     return angle::Result::Continue;
1529 }
1530 
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1531 angle::Result Texture::setEGLImageTarget(Context *context,
1532                                          TextureType type,
1533                                          egl::Image *imageTarget)
1534 {
1535     ASSERT(type == mState.mType);
1536     ASSERT(type == TextureType::_2D || type == TextureType::External);
1537 
1538     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1539     ANGLE_TRY(releaseTexImageInternal(context));
1540     ANGLE_TRY(orphanImages(context));
1541 
1542     ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1543 
1544     setTargetImage(context, imageTarget);
1545 
1546     Extents size(static_cast<int>(imageTarget->getWidth()),
1547                  static_cast<int>(imageTarget->getHeight()), 1);
1548 
1549     auto initState = imageTarget->sourceInitState();
1550 
1551     mState.clearImageDescs();
1552     mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1553                         ImageDesc(size, imageTarget->getFormat(), initState));
1554     signalDirtyStorage(initState);
1555 
1556     return angle::Result::Continue;
1557 }
1558 
getAttachmentSize(const ImageIndex & imageIndex) const1559 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1560 {
1561     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1562     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1563     // one that belongs to the first face of the cube map.
1564     if (imageIndex.isEntireLevelCubeMap())
1565     {
1566         // A cube map texture is cube complete if the following conditions all hold true:
1567         // - The levelbase arrays of each of the six texture images making up the cube map have
1568         //   identical, positive, and square dimensions.
1569         if (!mState.isCubeComplete())
1570         {
1571             return Extents();
1572         }
1573     }
1574 
1575     return mState.getImageDesc(imageIndex).size;
1576 }
1577 
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1578 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1579 {
1580     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1581     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1582     // one that belongs to the first face of the cube map.
1583     if (imageIndex.isEntireLevelCubeMap())
1584     {
1585         // A cube map texture is cube complete if the following conditions all hold true:
1586         // - The levelbase arrays were each specified with the same effective internal format.
1587         if (!mState.isCubeComplete())
1588         {
1589             return Format::Invalid();
1590         }
1591     }
1592     return mState.getImageDesc(imageIndex).format;
1593 }
1594 
getAttachmentSamples(const ImageIndex & imageIndex) const1595 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1596 {
1597     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1598     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1599     if (imageIndex.isEntireLevelCubeMap())
1600     {
1601         return 0;
1602     }
1603 
1604     return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1605 }
1606 
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1607 bool Texture::isRenderable(const Context *context,
1608                            GLenum binding,
1609                            const ImageIndex &imageIndex) const
1610 {
1611     if (isEGLImageTarget())
1612     {
1613         return ImageSibling::isRenderable(context, binding, imageIndex);
1614     }
1615     return getAttachmentFormat(binding, imageIndex)
1616         .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1617 }
1618 
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1619 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1620 {
1621     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1622     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1623     if (imageIndex.isEntireLevelCubeMap())
1624     {
1625         return true;
1626     }
1627 
1628     // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1629     // the same for all attached textures.
1630     return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1631 }
1632 
setBorderColor(const Context * context,const ColorGeneric & color)1633 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1634 {
1635     mState.mSamplerState.setBorderColor(color);
1636     signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1637 }
1638 
getBorderColor() const1639 const ColorGeneric &Texture::getBorderColor() const
1640 {
1641     return mState.mSamplerState.getBorderColor();
1642 }
1643 
setCrop(const gl::Rectangle & rect)1644 void Texture::setCrop(const gl::Rectangle &rect)
1645 {
1646     mState.setCrop(rect);
1647 }
1648 
getCrop() const1649 const gl::Rectangle &Texture::getCrop() const
1650 {
1651     return mState.getCrop();
1652 }
1653 
setGenerateMipmapHint(GLenum hint)1654 void Texture::setGenerateMipmapHint(GLenum hint)
1655 {
1656     mState.setGenerateMipmapHint(hint);
1657 }
1658 
getGenerateMipmapHint() const1659 GLenum Texture::getGenerateMipmapHint() const
1660 {
1661     return mState.getGenerateMipmapHint();
1662 }
1663 
onAttach(const Context * context)1664 void Texture::onAttach(const Context *context)
1665 {
1666     addRef();
1667 }
1668 
onDetach(const Context * context)1669 void Texture::onDetach(const Context *context)
1670 {
1671     release(context);
1672 }
1673 
getId() const1674 GLuint Texture::getId() const
1675 {
1676     return id();
1677 }
1678 
getNativeID() const1679 GLuint Texture::getNativeID() const
1680 {
1681     return mTexture->getNativeID();
1682 }
1683 
syncState(const Context * context)1684 angle::Result Texture::syncState(const Context *context)
1685 {
1686     ASSERT(hasAnyDirtyBit());
1687     ANGLE_TRY(mTexture->syncState(context, mDirtyBits));
1688     mDirtyBits.reset();
1689     return angle::Result::Continue;
1690 }
1691 
getAttachmentImpl() const1692 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1693 {
1694     return mTexture;
1695 }
1696 
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1697 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1698 {
1699     const auto &samplerState =
1700         optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1701     const auto &contextState = context->getState();
1702 
1703     if (contextState.getContextID() != mCompletenessCache.context ||
1704         !mCompletenessCache.samplerState.sameCompleteness(samplerState))
1705     {
1706         mCompletenessCache.context      = context->getState().getContextID();
1707         mCompletenessCache.samplerState = samplerState;
1708         mCompletenessCache.samplerComplete =
1709             mState.computeSamplerCompleteness(samplerState, contextState);
1710     }
1711 
1712     return mCompletenessCache.samplerComplete;
1713 }
1714 
SamplerCompletenessCache()1715 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1716     : context(0), samplerState(), samplerComplete(false)
1717 {}
1718 
invalidateCompletenessCache() const1719 void Texture::invalidateCompletenessCache() const
1720 {
1721     mCompletenessCache.context = 0;
1722 }
1723 
ensureInitialized(const Context * context)1724 angle::Result Texture::ensureInitialized(const Context *context)
1725 {
1726     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1727     {
1728         return angle::Result::Continue;
1729     }
1730 
1731     bool anyDirty = false;
1732 
1733     ImageIndexIterator it =
1734         ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
1735                                         ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1736     while (it.hasNext())
1737     {
1738         const ImageIndex index = it.next();
1739         ImageDesc &desc =
1740             mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
1741         if (desc.initState == InitState::MayNeedInit)
1742         {
1743             ASSERT(mState.mInitState == InitState::MayNeedInit);
1744             ANGLE_TRY(initializeContents(context, index));
1745             desc.initState = InitState::Initialized;
1746             anyDirty       = true;
1747         }
1748     }
1749     if (anyDirty)
1750     {
1751         signalDirtyStorage(InitState::Initialized);
1752     }
1753     mState.mInitState = InitState::Initialized;
1754 
1755     return angle::Result::Continue;
1756 }
1757 
initState(const ImageIndex & imageIndex) const1758 InitState Texture::initState(const ImageIndex &imageIndex) const
1759 {
1760     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1761     // we need to check all the related ImageDescs.
1762     if (imageIndex.isEntireLevelCubeMap())
1763     {
1764         const GLint levelIndex = imageIndex.getLevelIndex();
1765         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1766         {
1767             if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
1768             {
1769                 return InitState::MayNeedInit;
1770             }
1771         }
1772         return InitState::Initialized;
1773     }
1774 
1775     return mState.getImageDesc(imageIndex).initState;
1776 }
1777 
setInitState(const ImageIndex & imageIndex,InitState initState)1778 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1779 {
1780     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1781     // we need to update all the related ImageDescs.
1782     if (imageIndex.isEntireLevelCubeMap())
1783     {
1784         const GLint levelIndex = imageIndex.getLevelIndex();
1785         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1786         {
1787             setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
1788         }
1789     }
1790     else
1791     {
1792         ImageDesc newDesc = mState.getImageDesc(imageIndex);
1793         newDesc.initState = initState;
1794         mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
1795     }
1796 }
1797 
ensureSubImageInitialized(const Context * context,TextureTarget target,size_t level,const gl::Box & area)1798 angle::Result Texture::ensureSubImageInitialized(const Context *context,
1799                                                  TextureTarget target,
1800                                                  size_t level,
1801                                                  const gl::Box &area)
1802 {
1803     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1804     {
1805         return angle::Result::Continue;
1806     }
1807 
1808     // Pre-initialize the texture contents if necessary.
1809     // TODO(jmadill): Check if area overlaps the entire texture.
1810     ImageIndex imageIndex =
1811         ImageIndex::MakeFromTarget(target, static_cast<GLint>(level), area.depth);
1812     const auto &desc = mState.getImageDesc(imageIndex);
1813     if (desc.initState == InitState::MayNeedInit)
1814     {
1815         ASSERT(mState.mInitState == InitState::MayNeedInit);
1816         bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1817                                 area.width == desc.size.width && area.height == desc.size.height &&
1818                                 area.depth == desc.size.depth;
1819         if (!coversWholeImage)
1820         {
1821             ANGLE_TRY(initializeContents(context, imageIndex));
1822         }
1823         setInitState(imageIndex, InitState::Initialized);
1824     }
1825 
1826     return angle::Result::Continue;
1827 }
1828 
handleMipmapGenerationHint(Context * context,int level)1829 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
1830 {
1831 
1832     if (getGenerateMipmapHint() == GL_TRUE && level == 0)
1833     {
1834         ANGLE_TRY(generateMipmap(context));
1835     }
1836 
1837     return angle::Result::Continue;
1838 }
1839 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1840 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1841 {
1842     ASSERT(message == angle::SubjectMessage::SubjectChanged);
1843     mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
1844     signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1845 
1846     // Notify siblings that we are dirty.
1847     if (index == rx::kTextureImageImplObserverMessageIndex)
1848     {
1849         notifySiblings(message);
1850     }
1851 }
1852 }  // namespace gl
1853