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