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