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