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