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