• 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 {
IsPointSampled(const SamplerState & samplerState)27 bool IsPointSampled(const SamplerState &samplerState)
28 {
29     return (samplerState.getMagFilter() == GL_NEAREST &&
30             (samplerState.getMinFilter() == GL_NEAREST ||
31              samplerState.getMinFilter() == GL_NEAREST_MIPMAP_NEAREST));
32 }
33 
GetImageDescIndex(TextureTarget target,size_t level)34 size_t GetImageDescIndex(TextureTarget target, size_t level)
35 {
36     return IsCubeMapFaceTarget(target) ? (level * 6 + CubeMapTextureTargetToFaceIndex(target))
37                                        : level;
38 }
39 
DetermineInitState(const Context * context,Buffer * unpackBuffer,const uint8_t * pixels)40 InitState DetermineInitState(const Context *context, Buffer *unpackBuffer, const uint8_t *pixels)
41 {
42     // Can happen in tests.
43     if (!context || !context->isRobustResourceInitEnabled())
44     {
45         return InitState::Initialized;
46     }
47 
48     return (!pixels && !unpackBuffer) ? InitState::MayNeedInit : InitState::Initialized;
49 }
50 }  // namespace
51 
IsMipmapFiltered(const SamplerState & samplerState)52 bool IsMipmapFiltered(const SamplerState &samplerState)
53 {
54     switch (samplerState.getMinFilter())
55     {
56         case GL_NEAREST:
57         case GL_LINEAR:
58             return false;
59         case GL_NEAREST_MIPMAP_NEAREST:
60         case GL_LINEAR_MIPMAP_NEAREST:
61         case GL_NEAREST_MIPMAP_LINEAR:
62         case GL_LINEAR_MIPMAP_LINEAR:
63             return true;
64         default:
65             UNREACHABLE();
66             return false;
67     }
68 }
69 
SwizzleState()70 SwizzleState::SwizzleState()
71     : swizzleRed(GL_RED), swizzleGreen(GL_GREEN), swizzleBlue(GL_BLUE), swizzleAlpha(GL_ALPHA)
72 {}
73 
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)74 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
75     : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
76 {}
77 
swizzleRequired() const78 bool SwizzleState::swizzleRequired() const
79 {
80     return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
81            swizzleAlpha != GL_ALPHA;
82 }
83 
operator ==(const SwizzleState & other) const84 bool SwizzleState::operator==(const SwizzleState &other) const
85 {
86     return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
87            swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
88 }
89 
operator !=(const SwizzleState & other) const90 bool SwizzleState::operator!=(const SwizzleState &other) const
91 {
92     return !(*this == other);
93 }
94 
TextureState(TextureType type)95 TextureState::TextureState(TextureType type)
96     : mType(type),
97       mSamplerState(SamplerState::CreateDefaultForTarget(type)),
98       mSrgbOverride(SrgbOverride::Default),
99       mBaseLevel(0),
100       mMaxLevel(1000),
101       mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
102       mImmutableFormat(false),
103       mImmutableLevels(0),
104       mUsage(GL_NONE),
105       mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) * (type == TextureType::CubeMap ? 6 : 1)),
106       mCropRect(0, 0, 0, 0),
107       mGenerateMipmapHint(GL_FALSE),
108       mInitState(InitState::MayNeedInit),
109       mCachedSamplerFormat(SamplerFormat::InvalidEnum),
110       mCachedSamplerCompareMode(GL_NONE),
111       mCachedSamplerFormatValid(false)
112 {}
113 
~TextureState()114 TextureState::~TextureState() {}
115 
swizzleRequired() const116 bool TextureState::swizzleRequired() const
117 {
118     return mSwizzleState.swizzleRequired();
119 }
120 
getEffectiveBaseLevel() const121 GLuint TextureState::getEffectiveBaseLevel() const
122 {
123     if (mImmutableFormat)
124     {
125         // GLES 3.0.4 section 3.8.10
126         return std::min(mBaseLevel, mImmutableLevels - 1);
127     }
128     // Some classes use the effective base level to index arrays with level data. By clamping the
129     // effective base level to max levels these arrays need just one extra item to store properties
130     // that should be returned for all out-of-range base level values, instead of needing special
131     // handling for out-of-range base levels.
132     return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
133 }
134 
getEffectiveMaxLevel() const135 GLuint TextureState::getEffectiveMaxLevel() const
136 {
137     if (mImmutableFormat)
138     {
139         // GLES 3.0.4 section 3.8.10
140         GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
141         clampedMaxLevel        = std::min(clampedMaxLevel, mImmutableLevels - 1);
142         return clampedMaxLevel;
143     }
144     return mMaxLevel;
145 }
146 
getMipmapMaxLevel() const147 GLuint TextureState::getMipmapMaxLevel() const
148 {
149     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
150     GLuint expectedMipLevels       = 0;
151     if (mType == TextureType::_3D)
152     {
153         const int maxDim  = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
154                                     baseImageDesc.size.depth);
155         expectedMipLevels = static_cast<GLuint>(log2(maxDim));
156     }
157     else
158     {
159         expectedMipLevels = static_cast<GLuint>(
160             log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
161     }
162 
163     return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
164 }
165 
setBaseLevel(GLuint baseLevel)166 bool TextureState::setBaseLevel(GLuint baseLevel)
167 {
168     if (mBaseLevel != baseLevel)
169     {
170         mBaseLevel = baseLevel;
171         return true;
172     }
173     return false;
174 }
175 
setMaxLevel(GLuint maxLevel)176 bool TextureState::setMaxLevel(GLuint maxLevel)
177 {
178     if (mMaxLevel != maxLevel)
179     {
180         mMaxLevel = maxLevel;
181         return true;
182     }
183 
184     return false;
185 }
186 
187 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
188 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
189 // per-level checks begin at the base-level.
190 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const191 bool TextureState::isCubeComplete() const
192 {
193     ASSERT(mType == TextureType::CubeMap);
194 
195     angle::EnumIterator<TextureTarget> face = kCubeMapTextureTargetMin;
196     const ImageDesc &baseImageDesc          = getImageDesc(*face, getEffectiveBaseLevel());
197     if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
198     {
199         return false;
200     }
201 
202     ++face;
203 
204     for (; face != kAfterCubeMapTextureTargetMax; ++face)
205     {
206         const ImageDesc &faceImageDesc = getImageDesc(*face, getEffectiveBaseLevel());
207         if (faceImageDesc.size.width != baseImageDesc.size.width ||
208             faceImageDesc.size.height != baseImageDesc.size.height ||
209             !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
210         {
211             return false;
212         }
213     }
214 
215     return true;
216 }
217 
getBaseLevelDesc() const218 const ImageDesc &TextureState::getBaseLevelDesc() const
219 {
220     ASSERT(mType != TextureType::CubeMap || isCubeComplete());
221     return getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
222 }
223 
setCrop(const Rectangle & rect)224 void TextureState::setCrop(const Rectangle &rect)
225 {
226     mCropRect = rect;
227 }
228 
getCrop() const229 const Rectangle &TextureState::getCrop() const
230 {
231     return mCropRect;
232 }
233 
setGenerateMipmapHint(GLenum hint)234 void TextureState::setGenerateMipmapHint(GLenum hint)
235 {
236     mGenerateMipmapHint = hint;
237 }
238 
getGenerateMipmapHint() const239 GLenum TextureState::getGenerateMipmapHint() const
240 {
241     return mGenerateMipmapHint;
242 }
243 
computeRequiredSamplerFormat(const SamplerState & samplerState) const244 SamplerFormat TextureState::computeRequiredSamplerFormat(const SamplerState &samplerState) const
245 {
246     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
247     if ((baseImageDesc.format.info->format == GL_DEPTH_COMPONENT ||
248          baseImageDesc.format.info->format == GL_DEPTH_STENCIL) &&
249         samplerState.getCompareMode() != GL_NONE)
250     {
251         return SamplerFormat::Shadow;
252     }
253     else
254     {
255         switch (baseImageDesc.format.info->componentType)
256         {
257             case GL_UNSIGNED_NORMALIZED:
258             case GL_SIGNED_NORMALIZED:
259             case GL_FLOAT:
260                 return SamplerFormat::Float;
261             case GL_INT:
262                 return SamplerFormat::Signed;
263             case GL_UNSIGNED_INT:
264                 return SamplerFormat::Unsigned;
265             default:
266                 return SamplerFormat::InvalidEnum;
267         }
268     }
269 }
270 
computeSamplerCompleteness(const SamplerState & samplerState,const State & state) const271 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
272                                               const State &state) const
273 {
274     if (mBaseLevel > mMaxLevel)
275     {
276         return false;
277     }
278     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
279     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
280         baseImageDesc.size.depth == 0)
281     {
282         return false;
283     }
284     // The cases where the texture is incomplete because base level is out of range should be
285     // handled by the above condition.
286     ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
287 
288     if (mType == TextureType::CubeMap && baseImageDesc.size.width != baseImageDesc.size.height)
289     {
290         return false;
291     }
292 
293     // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
294     // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
295     // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
296     // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
297     // incomplete texture. So, we ignore filtering for multisample texture completeness here.
298     if (!IsMultisampled(mType) &&
299         !baseImageDesc.format.info->filterSupport(state.getClientVersion(),
300                                                   state.getExtensions()) &&
301         !IsPointSampled(samplerState))
302     {
303         return false;
304     }
305     bool npotSupport = state.getExtensions().textureNPOTOES || state.getClientMajorVersion() >= 3;
306     if (!npotSupport)
307     {
308         if ((samplerState.getWrapS() != GL_CLAMP_TO_EDGE &&
309              samplerState.getWrapS() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.width)) ||
310             (samplerState.getWrapT() != GL_CLAMP_TO_EDGE &&
311              samplerState.getWrapT() != GL_CLAMP_TO_BORDER && !isPow2(baseImageDesc.size.height)))
312         {
313             return false;
314         }
315     }
316 
317     if (mType != TextureType::_2DMultisample && IsMipmapFiltered(samplerState))
318     {
319         if (!npotSupport)
320         {
321             if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
322             {
323                 return false;
324             }
325         }
326 
327         if (!computeMipmapCompleteness())
328         {
329             return false;
330         }
331     }
332     else
333     {
334         if (mType == TextureType::CubeMap && !isCubeComplete())
335         {
336             return false;
337         }
338     }
339 
340     // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
341     // texture unit that would have been rejected by a call to TexParameter* for the texture bound
342     // to that unit, the behavior of the implementation is as if the texture were incomplete. For
343     // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
344     // sampler object bound to a texture unit and the texture bound to that unit is an external
345     // texture and EXT_EGL_image_external_wrap_modes is not enabled, the texture will be considered
346     // incomplete.
347     // Sampler object state which does not affect sampling for the type of texture bound
348     // to a texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect
349     // completeness.
350     if (mType == TextureType::External)
351     {
352         if (!state.getExtensions().eglImageExternalWrapModesEXT)
353         {
354             if (samplerState.getWrapS() != GL_CLAMP_TO_EDGE ||
355                 samplerState.getWrapT() != GL_CLAMP_TO_EDGE)
356             {
357                 return false;
358             }
359         }
360 
361         if (samplerState.getMinFilter() != GL_LINEAR && samplerState.getMinFilter() != GL_NEAREST)
362         {
363             return false;
364         }
365     }
366 
367     // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
368     // The internalformat specified for the texture arrays is a sized internal depth or
369     // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
370     // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
371     // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
372     if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
373         state.getClientMajorVersion() >= 3)
374     {
375         // Note: we restrict this validation to sized types. For the OES_depth_textures
376         // extension, due to some underspecification problems, we must allow linear filtering
377         // for legacy compatibility with WebGL 1.
378         // See http://crbug.com/649200
379         if (samplerState.getCompareMode() == GL_NONE && baseImageDesc.format.info->sized)
380         {
381             if ((samplerState.getMinFilter() != GL_NEAREST &&
382                  samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
383                 samplerState.getMagFilter() != GL_NEAREST)
384             {
385                 return false;
386             }
387         }
388     }
389 
390     // OpenGLES 3.1 spec section 8.16 states that a texture is not mipmap complete if:
391     // The internalformat specified for the texture is DEPTH_STENCIL format, the value of
392     // DEPTH_STENCIL_TEXTURE_MODE is STENCIL_INDEX, and either the magnification filter is
393     // not NEAREST or the minification filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
394     // However, the ES 3.1 spec differs from the statement above, because it is incorrect.
395     // See the issue at https://github.com/KhronosGroup/OpenGL-API/issues/33.
396     // For multismaple texture, filter state of multisample texture is ignored(11.1.3.3).
397     // So it shouldn't be judged as incomplete texture. So, we ignore filtering for multisample
398     // texture completeness here.
399     if (!IsMultisampled(mType) && baseImageDesc.format.info->depthBits > 0 &&
400         mDepthStencilTextureMode == GL_STENCIL_INDEX)
401     {
402         if ((samplerState.getMinFilter() != GL_NEAREST &&
403              samplerState.getMinFilter() != GL_NEAREST_MIPMAP_NEAREST) ||
404             samplerState.getMagFilter() != GL_NEAREST)
405         {
406             return false;
407         }
408     }
409 
410     return true;
411 }
412 
computeMipmapCompleteness() const413 bool TextureState::computeMipmapCompleteness() const
414 {
415     const GLuint maxLevel = getMipmapMaxLevel();
416 
417     for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
418     {
419         if (mType == TextureType::CubeMap)
420         {
421             for (TextureTarget face : AllCubeFaceTextureTargets())
422             {
423                 if (!computeLevelCompleteness(face, level))
424                 {
425                     return false;
426                 }
427             }
428         }
429         else
430         {
431             if (!computeLevelCompleteness(NonCubeTextureTypeToTarget(mType), level))
432             {
433                 return false;
434             }
435         }
436     }
437 
438     return true;
439 }
440 
computeLevelCompleteness(TextureTarget target,size_t level) const441 bool TextureState::computeLevelCompleteness(TextureTarget target, size_t level) const
442 {
443     ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
444 
445     if (mImmutableFormat)
446     {
447         return true;
448     }
449 
450     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
451     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
452         baseImageDesc.size.depth == 0)
453     {
454         return false;
455     }
456 
457     const ImageDesc &levelImageDesc = getImageDesc(target, level);
458     if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
459         levelImageDesc.size.depth == 0)
460     {
461         return false;
462     }
463 
464     if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
465     {
466         return false;
467     }
468 
469     ASSERT(level >= getEffectiveBaseLevel());
470     const size_t relativeLevel = level - getEffectiveBaseLevel();
471     if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
472     {
473         return false;
474     }
475 
476     if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
477     {
478         return false;
479     }
480 
481     if (mType == TextureType::_3D)
482     {
483         if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
484         {
485             return false;
486         }
487     }
488     else if (IsArrayTextureType(mType))
489     {
490         if (levelImageDesc.size.depth != baseImageDesc.size.depth)
491         {
492             return false;
493         }
494     }
495 
496     return true;
497 }
498 
getBaseImageTarget() const499 TextureTarget TextureState::getBaseImageTarget() const
500 {
501     return mType == TextureType::CubeMap ? kCubeMapTextureTargetMin
502                                          : NonCubeTextureTypeToTarget(mType);
503 }
504 
getEnabledLevelCount() const505 GLuint TextureState::getEnabledLevelCount() const
506 {
507     GLuint levelCount      = 0;
508     const GLuint baseLevel = getEffectiveBaseLevel();
509     const GLuint maxLevel  = std::min(getEffectiveMaxLevel(), getMipmapMaxLevel());
510 
511     // The mip chain will have either one or more sequential levels, or max levels,
512     // but not a sparse one.
513     for (size_t descIndex = baseLevel; descIndex < mImageDescs.size();)
514     {
515         if (!mImageDescs[descIndex].size.empty())
516         {
517             levelCount++;
518         }
519         descIndex = (mType == TextureType::CubeMap) ? descIndex + 6 : descIndex + 1;
520     }
521     // The original image already takes account into the levelCount.
522     levelCount = std::min(maxLevel - baseLevel + 1, levelCount);
523 
524     return levelCount;
525 }
526 
ImageDesc()527 ImageDesc::ImageDesc()
528     : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::MayNeedInit)
529 {}
530 
ImageDesc(const Extents & size,const Format & format,const InitState initState)531 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
532     : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
533 {}
534 
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)535 ImageDesc::ImageDesc(const Extents &size,
536                      const Format &format,
537                      const GLsizei samples,
538                      const bool fixedSampleLocations,
539                      const InitState initState)
540     : size(size),
541       format(format),
542       samples(samples),
543       fixedSampleLocations(fixedSampleLocations),
544       initState(initState)
545 {}
546 
getMemorySize() const547 GLint ImageDesc::getMemorySize() const
548 {
549     // Assume allocated size is around width * height * depth * samples * pixelBytes
550     angle::CheckedNumeric<GLint> levelSize = 1;
551     levelSize *= format.info->pixelBytes;
552     levelSize *= size.width;
553     levelSize *= size.height;
554     levelSize *= size.depth;
555     levelSize *= std::max(samples, 1);
556     return levelSize.ValueOrDefault(std::numeric_limits<GLint>::max());
557 }
558 
getImageDesc(TextureTarget target,size_t level) const559 const ImageDesc &TextureState::getImageDesc(TextureTarget target, size_t level) const
560 {
561     size_t descIndex = GetImageDescIndex(target, level);
562     ASSERT(descIndex < mImageDescs.size());
563     return mImageDescs[descIndex];
564 }
565 
setImageDesc(TextureTarget target,size_t level,const ImageDesc & desc)566 void TextureState::setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc)
567 {
568     size_t descIndex = GetImageDescIndex(target, level);
569     ASSERT(descIndex < mImageDescs.size());
570     mImageDescs[descIndex] = desc;
571     if (desc.initState == InitState::MayNeedInit)
572     {
573         mInitState = InitState::MayNeedInit;
574     }
575 }
576 
577 // Note that an ImageIndex that represents an entire level of a cube map corresponds to 6
578 // ImageDescs, so if the cube map is cube complete, we return the ImageDesc of the first cube
579 // face, and we don't allow using this function when the cube map is not cube complete.
getImageDesc(const ImageIndex & imageIndex) const580 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
581 {
582     if (imageIndex.isEntireLevelCubeMap())
583     {
584         ASSERT(isCubeComplete());
585         const GLint levelIndex = imageIndex.getLevelIndex();
586         return getImageDesc(kCubeMapTextureTargetMin, levelIndex);
587     }
588 
589     return getImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex());
590 }
591 
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)592 void TextureState::setImageDescChain(GLuint baseLevel,
593                                      GLuint maxLevel,
594                                      Extents baseSize,
595                                      const Format &format,
596                                      InitState initState)
597 {
598     for (GLuint level = baseLevel; level <= maxLevel; level++)
599     {
600         int relativeLevel = (level - baseLevel);
601         Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
602                           std::max<int>(baseSize.height >> relativeLevel, 1),
603                           (IsArrayTextureType(mType))
604                               ? baseSize.depth
605                               : std::max<int>(baseSize.depth >> relativeLevel, 1));
606         ImageDesc levelInfo(levelSize, format, initState);
607 
608         if (mType == TextureType::CubeMap)
609         {
610             for (TextureTarget face : AllCubeFaceTextureTargets())
611             {
612                 setImageDesc(face, level, levelInfo);
613             }
614         }
615         else
616         {
617             setImageDesc(NonCubeTextureTypeToTarget(mType), level, levelInfo);
618         }
619     }
620 }
621 
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)622 void TextureState::setImageDescChainMultisample(Extents baseSize,
623                                                 const Format &format,
624                                                 GLsizei samples,
625                                                 bool fixedSampleLocations,
626                                                 InitState initState)
627 {
628     ASSERT(mType == TextureType::_2DMultisample || mType == TextureType::_2DMultisampleArray);
629     ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
630     setImageDesc(NonCubeTextureTypeToTarget(mType), 0, levelInfo);
631 }
632 
clearImageDesc(TextureTarget target,size_t level)633 void TextureState::clearImageDesc(TextureTarget target, size_t level)
634 {
635     setImageDesc(target, level, ImageDesc());
636 }
637 
clearImageDescs()638 void TextureState::clearImageDescs()
639 {
640     for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
641     {
642         mImageDescs[descIndex] = ImageDesc();
643     }
644 }
645 
Texture(rx::GLImplFactory * factory,TextureID id,TextureType type)646 Texture::Texture(rx::GLImplFactory *factory, TextureID id, TextureType type)
647     : RefCountObject(factory->generateSerial(), id),
648       mState(type),
649       mTexture(factory->createTexture(mState)),
650       mImplObserver(this, rx::kTextureImageImplObserverMessageIndex),
651       mLabel(),
652       mBoundSurface(nullptr),
653       mBoundStream(nullptr)
654 {
655     mImplObserver.bind(mTexture);
656 
657     // Initially assume the implementation is dirty.
658     mDirtyBits.set(DIRTY_BIT_IMPLEMENTATION);
659 }
660 
onDestroy(const Context * context)661 void Texture::onDestroy(const Context *context)
662 {
663     if (mBoundSurface)
664     {
665         ANGLE_SWALLOW_ERR(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
666         mBoundSurface = nullptr;
667     }
668     if (mBoundStream)
669     {
670         mBoundStream->releaseTextures();
671         mBoundStream = nullptr;
672     }
673 
674     (void)(orphanImages(context));
675 
676     if (mTexture)
677     {
678         mTexture->onDestroy(context);
679     }
680 }
681 
~Texture()682 Texture::~Texture()
683 {
684     SafeDelete(mTexture);
685 }
686 
setLabel(const Context * context,const std::string & label)687 void Texture::setLabel(const Context *context, const std::string &label)
688 {
689     mLabel = label;
690     signalDirtyState(DIRTY_BIT_LABEL);
691 }
692 
getLabel() const693 const std::string &Texture::getLabel() const
694 {
695     return mLabel;
696 }
697 
setSwizzleRed(const Context * context,GLenum swizzleRed)698 void Texture::setSwizzleRed(const Context *context, GLenum swizzleRed)
699 {
700     mState.mSwizzleState.swizzleRed = swizzleRed;
701     signalDirtyState(DIRTY_BIT_SWIZZLE_RED);
702 }
703 
getSwizzleRed() const704 GLenum Texture::getSwizzleRed() const
705 {
706     return mState.mSwizzleState.swizzleRed;
707 }
708 
setSwizzleGreen(const Context * context,GLenum swizzleGreen)709 void Texture::setSwizzleGreen(const Context *context, GLenum swizzleGreen)
710 {
711     mState.mSwizzleState.swizzleGreen = swizzleGreen;
712     signalDirtyState(DIRTY_BIT_SWIZZLE_GREEN);
713 }
714 
getSwizzleGreen() const715 GLenum Texture::getSwizzleGreen() const
716 {
717     return mState.mSwizzleState.swizzleGreen;
718 }
719 
setSwizzleBlue(const Context * context,GLenum swizzleBlue)720 void Texture::setSwizzleBlue(const Context *context, GLenum swizzleBlue)
721 {
722     mState.mSwizzleState.swizzleBlue = swizzleBlue;
723     signalDirtyState(DIRTY_BIT_SWIZZLE_BLUE);
724 }
725 
getSwizzleBlue() const726 GLenum Texture::getSwizzleBlue() const
727 {
728     return mState.mSwizzleState.swizzleBlue;
729 }
730 
setSwizzleAlpha(const Context * context,GLenum swizzleAlpha)731 void Texture::setSwizzleAlpha(const Context *context, GLenum swizzleAlpha)
732 {
733     mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
734     signalDirtyState(DIRTY_BIT_SWIZZLE_ALPHA);
735 }
736 
getSwizzleAlpha() const737 GLenum Texture::getSwizzleAlpha() const
738 {
739     return mState.mSwizzleState.swizzleAlpha;
740 }
741 
setMinFilter(const Context * context,GLenum minFilter)742 void Texture::setMinFilter(const Context *context, GLenum minFilter)
743 {
744     mState.mSamplerState.setMinFilter(minFilter);
745     signalDirtyState(DIRTY_BIT_MIN_FILTER);
746 }
747 
getMinFilter() const748 GLenum Texture::getMinFilter() const
749 {
750     return mState.mSamplerState.getMinFilter();
751 }
752 
setMagFilter(const Context * context,GLenum magFilter)753 void Texture::setMagFilter(const Context *context, GLenum magFilter)
754 {
755     mState.mSamplerState.setMagFilter(magFilter);
756     signalDirtyState(DIRTY_BIT_MAG_FILTER);
757 }
758 
getMagFilter() const759 GLenum Texture::getMagFilter() const
760 {
761     return mState.mSamplerState.getMagFilter();
762 }
763 
setWrapS(const Context * context,GLenum wrapS)764 void Texture::setWrapS(const Context *context, GLenum wrapS)
765 {
766     mState.mSamplerState.setWrapS(wrapS);
767     signalDirtyState(DIRTY_BIT_WRAP_S);
768 }
769 
getWrapS() const770 GLenum Texture::getWrapS() const
771 {
772     return mState.mSamplerState.getWrapS();
773 }
774 
setWrapT(const Context * context,GLenum wrapT)775 void Texture::setWrapT(const Context *context, GLenum wrapT)
776 {
777     mState.mSamplerState.setWrapT(wrapT);
778     signalDirtyState(DIRTY_BIT_WRAP_T);
779 }
780 
getWrapT() const781 GLenum Texture::getWrapT() const
782 {
783     return mState.mSamplerState.getWrapT();
784 }
785 
setWrapR(const Context * context,GLenum wrapR)786 void Texture::setWrapR(const Context *context, GLenum wrapR)
787 {
788     mState.mSamplerState.setWrapR(wrapR);
789     signalDirtyState(DIRTY_BIT_WRAP_R);
790 }
791 
getWrapR() const792 GLenum Texture::getWrapR() const
793 {
794     return mState.mSamplerState.getWrapR();
795 }
796 
setMaxAnisotropy(const Context * context,float maxAnisotropy)797 void Texture::setMaxAnisotropy(const Context *context, float maxAnisotropy)
798 {
799     mState.mSamplerState.setMaxAnisotropy(maxAnisotropy);
800     signalDirtyState(DIRTY_BIT_MAX_ANISOTROPY);
801 }
802 
getMaxAnisotropy() const803 float Texture::getMaxAnisotropy() const
804 {
805     return mState.mSamplerState.getMaxAnisotropy();
806 }
807 
setMinLod(const Context * context,GLfloat minLod)808 void Texture::setMinLod(const Context *context, GLfloat minLod)
809 {
810     mState.mSamplerState.setMinLod(minLod);
811     signalDirtyState(DIRTY_BIT_MIN_LOD);
812 }
813 
getMinLod() const814 GLfloat Texture::getMinLod() const
815 {
816     return mState.mSamplerState.getMinLod();
817 }
818 
setMaxLod(const Context * context,GLfloat maxLod)819 void Texture::setMaxLod(const Context *context, GLfloat maxLod)
820 {
821     mState.mSamplerState.setMaxLod(maxLod);
822     signalDirtyState(DIRTY_BIT_MAX_LOD);
823 }
824 
getMaxLod() const825 GLfloat Texture::getMaxLod() const
826 {
827     return mState.mSamplerState.getMaxLod();
828 }
829 
setCompareMode(const Context * context,GLenum compareMode)830 void Texture::setCompareMode(const Context *context, GLenum compareMode)
831 {
832     mState.mSamplerState.setCompareMode(compareMode);
833     signalDirtyState(DIRTY_BIT_COMPARE_MODE);
834 }
835 
getCompareMode() const836 GLenum Texture::getCompareMode() const
837 {
838     return mState.mSamplerState.getCompareMode();
839 }
840 
setCompareFunc(const Context * context,GLenum compareFunc)841 void Texture::setCompareFunc(const Context *context, GLenum compareFunc)
842 {
843     mState.mSamplerState.setCompareFunc(compareFunc);
844     signalDirtyState(DIRTY_BIT_COMPARE_FUNC);
845 }
846 
getCompareFunc() const847 GLenum Texture::getCompareFunc() const
848 {
849     return mState.mSamplerState.getCompareFunc();
850 }
851 
setSRGBDecode(const Context * context,GLenum sRGBDecode)852 void Texture::setSRGBDecode(const Context *context, GLenum sRGBDecode)
853 {
854     mState.mSamplerState.setSRGBDecode(sRGBDecode);
855     signalDirtyState(DIRTY_BIT_SRGB_DECODE);
856 }
857 
getSRGBDecode() const858 GLenum Texture::getSRGBDecode() const
859 {
860     return mState.mSamplerState.getSRGBDecode();
861 }
862 
setSRGBOverride(const Context * context,GLenum sRGBOverride)863 void Texture::setSRGBOverride(const Context *context, GLenum sRGBOverride)
864 {
865     SrgbOverride oldOverride = mState.mSrgbOverride;
866     mState.mSrgbOverride =
867         (sRGBOverride == GL_SRGB) ? SrgbOverride::Enabled : SrgbOverride::Default;
868     if (mState.mSrgbOverride != oldOverride)
869     {
870         signalDirtyState(DIRTY_BIT_SRGB_OVERRIDE);
871     }
872 }
873 
getSRGBOverride() const874 GLenum Texture::getSRGBOverride() const
875 {
876     return (mState.mSrgbOverride == SrgbOverride::Enabled) ? GL_SRGB : GL_NONE;
877 }
878 
getSamplerState() const879 const SamplerState &Texture::getSamplerState() const
880 {
881     return mState.mSamplerState;
882 }
883 
setBaseLevel(const Context * context,GLuint baseLevel)884 angle::Result Texture::setBaseLevel(const Context *context, GLuint baseLevel)
885 {
886     if (mState.setBaseLevel(baseLevel))
887     {
888         ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
889         signalDirtyState(DIRTY_BIT_BASE_LEVEL);
890     }
891 
892     return angle::Result::Continue;
893 }
894 
getBaseLevel() const895 GLuint Texture::getBaseLevel() const
896 {
897     return mState.mBaseLevel;
898 }
899 
setMaxLevel(const Context * context,GLuint maxLevel)900 void Texture::setMaxLevel(const Context *context, GLuint maxLevel)
901 {
902     if (mState.setMaxLevel(maxLevel))
903     {
904         signalDirtyState(DIRTY_BIT_MAX_LEVEL);
905     }
906 }
907 
getMaxLevel() const908 GLuint Texture::getMaxLevel() const
909 {
910     return mState.mMaxLevel;
911 }
912 
setDepthStencilTextureMode(const Context * context,GLenum mode)913 void Texture::setDepthStencilTextureMode(const Context *context, GLenum mode)
914 {
915     if (mState.mDepthStencilTextureMode != mode)
916     {
917         mState.mDepthStencilTextureMode = mode;
918         signalDirtyState(DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE);
919     }
920 }
921 
getDepthStencilTextureMode() const922 GLenum Texture::getDepthStencilTextureMode() const
923 {
924     return mState.mDepthStencilTextureMode;
925 }
926 
getImmutableFormat() const927 bool Texture::getImmutableFormat() const
928 {
929     return mState.mImmutableFormat;
930 }
931 
getImmutableLevels() const932 GLuint Texture::getImmutableLevels() const
933 {
934     return mState.mImmutableLevels;
935 }
936 
setUsage(const Context * context,GLenum usage)937 void Texture::setUsage(const Context *context, GLenum usage)
938 {
939     mState.mUsage = usage;
940     signalDirtyState(DIRTY_BIT_USAGE);
941 }
942 
getUsage() const943 GLenum Texture::getUsage() const
944 {
945     return mState.mUsage;
946 }
947 
getTextureState() const948 const TextureState &Texture::getTextureState() const
949 {
950     return mState;
951 }
952 
getExtents(TextureTarget target,size_t level) const953 const Extents &Texture::getExtents(TextureTarget target, size_t level) const
954 {
955     ASSERT(TextureTargetToType(target) == mState.mType);
956     return mState.getImageDesc(target, level).size;
957 }
958 
getWidth(TextureTarget target,size_t level) const959 size_t Texture::getWidth(TextureTarget target, size_t level) const
960 {
961     ASSERT(TextureTargetToType(target) == mState.mType);
962     return mState.getImageDesc(target, level).size.width;
963 }
964 
getHeight(TextureTarget target,size_t level) const965 size_t Texture::getHeight(TextureTarget target, size_t level) const
966 {
967     ASSERT(TextureTargetToType(target) == mState.mType);
968     return mState.getImageDesc(target, level).size.height;
969 }
970 
getDepth(TextureTarget target,size_t level) const971 size_t Texture::getDepth(TextureTarget target, size_t level) const
972 {
973     ASSERT(TextureTargetToType(target) == mState.mType);
974     return mState.getImageDesc(target, level).size.depth;
975 }
976 
getFormat(TextureTarget target,size_t level) const977 const Format &Texture::getFormat(TextureTarget target, size_t level) const
978 {
979     ASSERT(TextureTargetToType(target) == mState.mType);
980     return mState.getImageDesc(target, level).format;
981 }
982 
getSamples(TextureTarget target,size_t level) const983 GLsizei Texture::getSamples(TextureTarget target, size_t level) const
984 {
985     ASSERT(TextureTargetToType(target) == mState.mType);
986     return mState.getImageDesc(target, level).samples;
987 }
988 
getFixedSampleLocations(TextureTarget target,size_t level) const989 bool Texture::getFixedSampleLocations(TextureTarget target, size_t level) const
990 {
991     ASSERT(TextureTargetToType(target) == mState.mType);
992     return mState.getImageDesc(target, level).fixedSampleLocations;
993 }
994 
getMipmapMaxLevel() const995 GLuint Texture::getMipmapMaxLevel() const
996 {
997     return mState.getMipmapMaxLevel();
998 }
999 
isMipmapComplete() const1000 bool Texture::isMipmapComplete() const
1001 {
1002     return mState.computeMipmapCompleteness();
1003 }
1004 
getBoundSurface() const1005 egl::Surface *Texture::getBoundSurface() const
1006 {
1007     return mBoundSurface;
1008 }
1009 
getBoundStream() const1010 egl::Stream *Texture::getBoundStream() const
1011 {
1012     return mBoundStream;
1013 }
1014 
getMemorySize() const1015 GLint Texture::getMemorySize() const
1016 {
1017     GLint implSize = mTexture->getMemorySize();
1018     if (implSize > 0)
1019     {
1020         return implSize;
1021     }
1022 
1023     angle::CheckedNumeric<GLint> size = 0;
1024     for (const ImageDesc &imageDesc : mState.mImageDescs)
1025     {
1026         size += imageDesc.getMemorySize();
1027     }
1028     return size.ValueOrDefault(std::numeric_limits<GLint>::max());
1029 }
1030 
getLevelMemorySize(TextureTarget target,GLint level) const1031 GLint Texture::getLevelMemorySize(TextureTarget target, GLint level) const
1032 {
1033     GLint implSize = mTexture->getLevelMemorySize(target, level);
1034     if (implSize > 0)
1035     {
1036         return implSize;
1037     }
1038 
1039     return mState.getImageDesc(target, level).getMemorySize();
1040 }
1041 
signalDirtyStorage(InitState initState)1042 void Texture::signalDirtyStorage(InitState initState)
1043 {
1044     mState.mInitState = initState;
1045     invalidateCompletenessCache();
1046     mState.mCachedSamplerFormatValid = false;
1047     onStateChange(angle::SubjectMessage::SubjectChanged);
1048 }
1049 
signalDirtyState(size_t dirtyBit)1050 void Texture::signalDirtyState(size_t dirtyBit)
1051 {
1052     mDirtyBits.set(dirtyBit);
1053     invalidateCompletenessCache();
1054     mState.mCachedSamplerFormatValid = false;
1055     onStateChange(angle::SubjectMessage::DirtyBitsFlagged);
1056 }
1057 
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)1058 angle::Result Texture::setImage(Context *context,
1059                                 const PixelUnpackState &unpackState,
1060                                 Buffer *unpackBuffer,
1061                                 TextureTarget target,
1062                                 GLint level,
1063                                 GLenum internalFormat,
1064                                 const Extents &size,
1065                                 GLenum format,
1066                                 GLenum type,
1067                                 const uint8_t *pixels)
1068 {
1069     ASSERT(TextureTargetToType(target) == mState.mType);
1070 
1071     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1072     ANGLE_TRY(releaseTexImageInternal(context));
1073     ANGLE_TRY(orphanImages(context));
1074 
1075     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1076 
1077     ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size, format, type, unpackState,
1078                                  unpackBuffer, pixels));
1079 
1080     InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1081     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1082 
1083     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1084 
1085     signalDirtyStorage(initState);
1086 
1087     return angle::Result::Continue;
1088 }
1089 
setSubImage(Context * context,const PixelUnpackState & unpackState,Buffer * unpackBuffer,TextureTarget target,GLint level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)1090 angle::Result Texture::setSubImage(Context *context,
1091                                    const PixelUnpackState &unpackState,
1092                                    Buffer *unpackBuffer,
1093                                    TextureTarget target,
1094                                    GLint level,
1095                                    const Box &area,
1096                                    GLenum format,
1097                                    GLenum type,
1098                                    const uint8_t *pixels)
1099 {
1100     ASSERT(TextureTargetToType(target) == mState.mType);
1101 
1102     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1103     ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1104 
1105     ANGLE_TRY(mTexture->setSubImage(context, index, area, format, type, unpackState, unpackBuffer,
1106                                     pixels));
1107 
1108     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1109 
1110     onStateChange(angle::SubjectMessage::ContentsChanged);
1111 
1112     return angle::Result::Continue;
1113 }
1114 
setCompressedImage(Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)1115 angle::Result Texture::setCompressedImage(Context *context,
1116                                           const PixelUnpackState &unpackState,
1117                                           TextureTarget target,
1118                                           GLint level,
1119                                           GLenum internalFormat,
1120                                           const Extents &size,
1121                                           size_t imageSize,
1122                                           const uint8_t *pixels)
1123 {
1124     ASSERT(TextureTargetToType(target) == mState.mType);
1125 
1126     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1127     ANGLE_TRY(releaseTexImageInternal(context));
1128     ANGLE_TRY(orphanImages(context));
1129 
1130     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1131 
1132     ANGLE_TRY(mTexture->setCompressedImage(context, index, internalFormat, size, unpackState,
1133                                            imageSize, pixels));
1134 
1135     Buffer *unpackBuffer = context->getState().getTargetBuffer(BufferBinding::PixelUnpack);
1136 
1137     InitState initState = DetermineInitState(context, unpackBuffer, pixels);
1138     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
1139     signalDirtyStorage(initState);
1140 
1141     return angle::Result::Continue;
1142 }
1143 
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,TextureTarget target,GLint level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)1144 angle::Result Texture::setCompressedSubImage(const Context *context,
1145                                              const PixelUnpackState &unpackState,
1146                                              TextureTarget target,
1147                                              GLint level,
1148                                              const Box &area,
1149                                              GLenum format,
1150                                              size_t imageSize,
1151                                              const uint8_t *pixels)
1152 {
1153     ASSERT(TextureTargetToType(target) == mState.mType);
1154 
1155     ImageIndex index = ImageIndex::MakeFromTarget(target, level, area.depth);
1156     ANGLE_TRY(ensureSubImageInitialized(context, index, area));
1157 
1158     ANGLE_TRY(mTexture->setCompressedSubImage(context, index, area, format, unpackState, imageSize,
1159                                               pixels));
1160 
1161     onStateChange(angle::SubjectMessage::ContentsChanged);
1162 
1163     return angle::Result::Continue;
1164 }
1165 
copyImage(Context * context,TextureTarget target,GLint level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)1166 angle::Result Texture::copyImage(Context *context,
1167                                  TextureTarget target,
1168                                  GLint level,
1169                                  const Rectangle &sourceArea,
1170                                  GLenum internalFormat,
1171                                  Framebuffer *source)
1172 {
1173     ASSERT(TextureTargetToType(target) == mState.mType);
1174 
1175     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1176     ANGLE_TRY(releaseTexImageInternal(context));
1177     ANGLE_TRY(orphanImages(context));
1178 
1179     ImageIndex index = ImageIndex::MakeFromTarget(target, level, 1);
1180 
1181     const InternalFormat &internalFormatInfo =
1182         GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1183 
1184     // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1185     // other pixels untouched. For safety in robust resource initialization, assume that that
1186     // clipping is going to occur when computing the region for which to ensure initialization. If
1187     // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1188     // going to be set during the copy operation.
1189     Box destBox;
1190     if (context->isRobustResourceInitEnabled())
1191     {
1192         Extents fbSize = source->getReadColorAttachment()->getSize();
1193         Rectangle clippedArea;
1194         if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1195         {
1196             const Offset clippedOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y,
1197                                        0);
1198             destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1199                           clippedArea.height, 1);
1200         }
1201     }
1202 
1203     // If we need to initialize the destination texture we split the call into a create call,
1204     // an initializeContents call, and then a copySubImage call. This ensures the destination
1205     // texture exists before we try to clear it.
1206     Extents size(sourceArea.width, sourceArea.height, 1);
1207     if (doesSubImageNeedInit(context, index, destBox))
1208     {
1209         ANGLE_TRY(mTexture->setImage(context, index, internalFormat, size,
1210                                      internalFormatInfo.format, internalFormatInfo.type,
1211                                      PixelUnpackState(), nullptr, nullptr));
1212         mState.setImageDesc(target, level,
1213                             ImageDesc(size, Format(internalFormatInfo), InitState::MayNeedInit));
1214         ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1215         ANGLE_TRY(mTexture->copySubImage(context, index, Offset(), sourceArea, source));
1216     }
1217     else
1218     {
1219         ANGLE_TRY(mTexture->copyImage(context, index, sourceArea, internalFormat, source));
1220     }
1221 
1222     mState.setImageDesc(target, level,
1223                         ImageDesc(size, Format(internalFormatInfo), InitState::Initialized));
1224 
1225     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1226 
1227     // Because this could affect the texture storage we might need to init other layers/levels.
1228     signalDirtyStorage(InitState::MayNeedInit);
1229 
1230     return angle::Result::Continue;
1231 }
1232 
copySubImage(Context * context,const ImageIndex & index,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1233 angle::Result Texture::copySubImage(Context *context,
1234                                     const ImageIndex &index,
1235                                     const Offset &destOffset,
1236                                     const Rectangle &sourceArea,
1237                                     Framebuffer *source)
1238 {
1239     ASSERT(TextureTargetToType(index.getTarget()) == mState.mType);
1240 
1241     // Most if not all renderers clip these copies to the size of the source framebuffer, leaving
1242     // other pixels untouched. For safety in robust resource initialization, assume that that
1243     // clipping is going to occur when computing the region for which to ensure initialization. If
1244     // the copy lies entirely off the source framebuffer, initialize as though a zero-size box is
1245     // going to be set during the copy operation. Note that this assumes that
1246     // ensureSubImageInitialized ensures initialization of the entire destination texture, and not
1247     // just a sub-region.
1248     Box destBox;
1249     if (context->isRobustResourceInitEnabled())
1250     {
1251         Extents fbSize = source->getReadColorAttachment()->getSize();
1252         Rectangle clippedArea;
1253         if (ClipRectangle(sourceArea, Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1254         {
1255             const Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1256                                        destOffset.y + clippedArea.y - sourceArea.y, 0);
1257             destBox = Box(clippedOffset.x, clippedOffset.y, clippedOffset.z, clippedArea.width,
1258                           clippedArea.height, 1);
1259         }
1260     }
1261 
1262     ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1263 
1264     ANGLE_TRY(mTexture->copySubImage(context, index, destOffset, sourceArea, source));
1265     ANGLE_TRY(handleMipmapGenerationHint(context, index.getLevelIndex()));
1266 
1267     onStateChange(angle::SubjectMessage::ContentsChanged);
1268 
1269     return angle::Result::Continue;
1270 }
1271 
copyTexture(Context * context,TextureTarget target,GLint level,GLenum internalFormat,GLenum type,GLint sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1272 angle::Result Texture::copyTexture(Context *context,
1273                                    TextureTarget target,
1274                                    GLint level,
1275                                    GLenum internalFormat,
1276                                    GLenum type,
1277                                    GLint sourceLevel,
1278                                    bool unpackFlipY,
1279                                    bool unpackPremultiplyAlpha,
1280                                    bool unpackUnmultiplyAlpha,
1281                                    Texture *source)
1282 {
1283     ASSERT(TextureTargetToType(target) == mState.mType);
1284     ASSERT(source->getType() != TextureType::CubeMap);
1285 
1286     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1287     ANGLE_TRY(releaseTexImageInternal(context));
1288     ANGLE_TRY(orphanImages(context));
1289 
1290     // Initialize source texture.
1291     // Note: we don't have a way to notify which portions of the image changed currently.
1292     ANGLE_TRY(source->ensureInitialized(context));
1293 
1294     ImageIndex index = ImageIndex::MakeFromTarget(target, level, ImageIndex::kEntireLevel);
1295 
1296     ANGLE_TRY(mTexture->copyTexture(context, index, internalFormat, type, sourceLevel, unpackFlipY,
1297                                     unpackPremultiplyAlpha, unpackUnmultiplyAlpha, source));
1298 
1299     const auto &sourceDesc =
1300         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1301     const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1302     mState.setImageDesc(
1303         target, level,
1304         ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1305 
1306     signalDirtyStorage(InitState::Initialized);
1307 
1308     return angle::Result::Continue;
1309 }
1310 
copySubTexture(const Context * context,TextureTarget target,GLint level,const Offset & destOffset,GLint sourceLevel,const Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1311 angle::Result Texture::copySubTexture(const Context *context,
1312                                       TextureTarget target,
1313                                       GLint level,
1314                                       const Offset &destOffset,
1315                                       GLint sourceLevel,
1316                                       const Box &sourceBox,
1317                                       bool unpackFlipY,
1318                                       bool unpackPremultiplyAlpha,
1319                                       bool unpackUnmultiplyAlpha,
1320                                       Texture *source)
1321 {
1322     ASSERT(TextureTargetToType(target) == mState.mType);
1323 
1324     // Ensure source is initialized.
1325     ANGLE_TRY(source->ensureInitialized(context));
1326 
1327     Box destBox(destOffset.x, destOffset.y, destOffset.z, sourceBox.width, sourceBox.height,
1328                 sourceBox.depth);
1329     ImageIndex index = ImageIndex::MakeFromTarget(target, level, sourceBox.depth);
1330     ANGLE_TRY(ensureSubImageInitialized(context, index, destBox));
1331 
1332     ANGLE_TRY(mTexture->copySubTexture(context, index, destOffset, sourceLevel, sourceBox,
1333                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1334                                        source));
1335 
1336     onStateChange(angle::SubjectMessage::ContentsChanged);
1337 
1338     return angle::Result::Continue;
1339 }
1340 
copyCompressedTexture(Context * context,const Texture * source)1341 angle::Result Texture::copyCompressedTexture(Context *context, const Texture *source)
1342 {
1343     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1344     ANGLE_TRY(releaseTexImageInternal(context));
1345     ANGLE_TRY(orphanImages(context));
1346 
1347     ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1348 
1349     ASSERT(source->getType() != TextureType::CubeMap && getType() != TextureType::CubeMap);
1350     const auto &sourceDesc =
1351         source->mState.getImageDesc(NonCubeTextureTypeToTarget(source->getType()), 0);
1352     mState.setImageDesc(NonCubeTextureTypeToTarget(getType()), 0, sourceDesc);
1353 
1354     return angle::Result::Continue;
1355 }
1356 
setStorage(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size)1357 angle::Result Texture::setStorage(Context *context,
1358                                   TextureType type,
1359                                   GLsizei levels,
1360                                   GLenum internalFormat,
1361                                   const Extents &size)
1362 {
1363     ASSERT(type == mState.mType);
1364 
1365     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1366     ANGLE_TRY(releaseTexImageInternal(context));
1367     ANGLE_TRY(orphanImages(context));
1368 
1369     mState.mImmutableFormat = true;
1370     mState.mImmutableLevels = static_cast<GLuint>(levels);
1371 
1372     ANGLE_TRY(mTexture->setStorage(context, type, levels, internalFormat, size));
1373 
1374     mState.clearImageDescs();
1375     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1376                              InitState::MayNeedInit);
1377 
1378     // Changing the texture to immutable can trigger a change in the base and max levels:
1379     // GLES 3.0.4 section 3.8.10 pg 158:
1380     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1381     // clamped to the range[levelbase;levels].
1382     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1383     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1384 
1385     signalDirtyStorage(InitState::MayNeedInit);
1386 
1387     return angle::Result::Continue;
1388 }
1389 
setImageExternal(Context * context,TextureTarget target,GLint level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type)1390 angle::Result Texture::setImageExternal(Context *context,
1391                                         TextureTarget target,
1392                                         GLint level,
1393                                         GLenum internalFormat,
1394                                         const Extents &size,
1395                                         GLenum format,
1396                                         GLenum type)
1397 {
1398     ASSERT(TextureTargetToType(target) == mState.mType);
1399 
1400     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1401     ANGLE_TRY(releaseTexImageInternal(context));
1402     ANGLE_TRY(orphanImages(context));
1403 
1404     ImageIndex index = ImageIndex::MakeFromTarget(target, level, size.depth);
1405 
1406     ANGLE_TRY(mTexture->setImageExternal(context, index, internalFormat, size, format, type));
1407 
1408     InitState initState = InitState::Initialized;
1409     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
1410 
1411     ANGLE_TRY(handleMipmapGenerationHint(context, level));
1412 
1413     signalDirtyStorage(initState);
1414 
1415     return angle::Result::Continue;
1416 }
1417 
setStorageMultisample(Context * context,TextureType type,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1418 angle::Result Texture::setStorageMultisample(Context *context,
1419                                              TextureType type,
1420                                              GLsizei samples,
1421                                              GLint internalFormat,
1422                                              const Extents &size,
1423                                              bool fixedSampleLocations)
1424 {
1425     ASSERT(type == mState.mType);
1426 
1427     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1428     ANGLE_TRY(releaseTexImageInternal(context));
1429     ANGLE_TRY(orphanImages(context));
1430 
1431     // Potentially adjust "samples" to a supported value
1432     const TextureCaps &formatCaps = context->getTextureCaps().get(internalFormat);
1433     samples                       = formatCaps.getNearestSamples(samples);
1434 
1435     ANGLE_TRY(mTexture->setStorageMultisample(context, type, samples, internalFormat, size,
1436                                               fixedSampleLocations));
1437 
1438     mState.mImmutableFormat = true;
1439     mState.mImmutableLevels = static_cast<GLuint>(1);
1440     mState.clearImageDescs();
1441     mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1442                                         InitState::MayNeedInit);
1443 
1444     signalDirtyStorage(InitState::MayNeedInit);
1445 
1446     return angle::Result::Continue;
1447 }
1448 
setStorageExternalMemory(Context * context,TextureType type,GLsizei levels,GLenum internalFormat,const Extents & size,MemoryObject * memoryObject,GLuint64 offset)1449 angle::Result Texture::setStorageExternalMemory(Context *context,
1450                                                 TextureType type,
1451                                                 GLsizei levels,
1452                                                 GLenum internalFormat,
1453                                                 const Extents &size,
1454                                                 MemoryObject *memoryObject,
1455                                                 GLuint64 offset)
1456 {
1457     ASSERT(type == mState.mType);
1458 
1459     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1460     ANGLE_TRY(releaseTexImageInternal(context));
1461     ANGLE_TRY(orphanImages(context));
1462 
1463     ANGLE_TRY(mTexture->setStorageExternalMemory(context, type, levels, internalFormat, size,
1464                                                  memoryObject, offset));
1465 
1466     mState.mImmutableFormat = true;
1467     mState.mImmutableLevels = static_cast<GLuint>(levels);
1468     mState.clearImageDescs();
1469     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1470                              InitState::MayNeedInit);
1471 
1472     // Changing the texture to immutable can trigger a change in the base and max levels:
1473     // GLES 3.0.4 section 3.8.10 pg 158:
1474     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1475     // clamped to the range[levelbase;levels].
1476     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1477     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1478 
1479     signalDirtyStorage(InitState::Initialized);
1480 
1481     return angle::Result::Continue;
1482 }
1483 
generateMipmap(Context * context)1484 angle::Result Texture::generateMipmap(Context *context)
1485 {
1486     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1487     ANGLE_TRY(releaseTexImageInternal(context));
1488 
1489     // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1490     // is not mip complete.
1491     if (!isMipmapComplete())
1492     {
1493         ANGLE_TRY(orphanImages(context));
1494     }
1495 
1496     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1497     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1498 
1499     if (maxLevel <= baseLevel)
1500     {
1501         return angle::Result::Continue;
1502     }
1503 
1504     if (hasAnyDirtyBit())
1505     {
1506         ANGLE_TRY(syncState(context));
1507     }
1508 
1509     // Clear the base image(s) immediately if needed
1510     if (context->isRobustResourceInitEnabled())
1511     {
1512         ImageIndexIterator it =
1513             ImageIndexIterator::MakeGeneric(mState.mType, baseLevel, baseLevel + 1,
1514                                             ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1515         while (it.hasNext())
1516         {
1517             const ImageIndex index = it.next();
1518             const ImageDesc &desc  = mState.getImageDesc(index.getTarget(), index.getLevelIndex());
1519 
1520             if (desc.initState == InitState::MayNeedInit)
1521             {
1522                 ANGLE_TRY(initializeContents(context, index));
1523             }
1524         }
1525     }
1526 
1527     ANGLE_TRY(mTexture->generateMipmap(context));
1528 
1529     // Propagate the format and size of the bsae mip to the smaller ones. Cube maps are guaranteed
1530     // to have faces of the same size and format so any faces can be picked.
1531     const ImageDesc &baseImageInfo = mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1532     mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1533                              InitState::Initialized);
1534 
1535     signalDirtyStorage(InitState::Initialized);
1536 
1537     return angle::Result::Continue;
1538 }
1539 
bindTexImageFromSurface(Context * context,egl::Surface * surface)1540 angle::Result Texture::bindTexImageFromSurface(Context *context, egl::Surface *surface)
1541 {
1542     ASSERT(surface);
1543 
1544     if (mBoundSurface)
1545     {
1546         ANGLE_TRY(releaseTexImageFromSurface(context));
1547     }
1548 
1549     ANGLE_TRY(mTexture->bindTexImage(context, surface));
1550     mBoundSurface = surface;
1551 
1552     // Set the image info to the size and format of the surface
1553     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1554     Extents size(surface->getWidth(), surface->getHeight(), 1);
1555     ImageDesc desc(size, surface->getBindTexImageFormat(), InitState::Initialized);
1556     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0, desc);
1557     signalDirtyStorage(InitState::Initialized);
1558     return angle::Result::Continue;
1559 }
1560 
releaseTexImageFromSurface(const Context * context)1561 angle::Result Texture::releaseTexImageFromSurface(const Context *context)
1562 {
1563     ASSERT(mBoundSurface);
1564     mBoundSurface = nullptr;
1565     ANGLE_TRY(mTexture->releaseTexImage(context));
1566 
1567     // Erase the image info for level 0
1568     ASSERT(mState.mType == TextureType::_2D || mState.mType == TextureType::Rectangle);
1569     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1570     signalDirtyStorage(InitState::Initialized);
1571     return angle::Result::Continue;
1572 }
1573 
bindStream(egl::Stream * stream)1574 void Texture::bindStream(egl::Stream *stream)
1575 {
1576     ASSERT(stream);
1577 
1578     // It should not be possible to bind a texture already bound to another stream
1579     ASSERT(mBoundStream == nullptr);
1580 
1581     mBoundStream = stream;
1582 
1583     ASSERT(mState.mType == TextureType::External);
1584 }
1585 
releaseStream()1586 void Texture::releaseStream()
1587 {
1588     ASSERT(mBoundStream);
1589     mBoundStream = nullptr;
1590 }
1591 
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1592 angle::Result Texture::acquireImageFromStream(const Context *context,
1593                                               const egl::Stream::GLTextureDescription &desc)
1594 {
1595     ASSERT(mBoundStream != nullptr);
1596     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, mBoundStream, desc));
1597 
1598     Extents size(desc.width, desc.height, 1);
1599     mState.setImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0,
1600                         ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1601     signalDirtyStorage(InitState::Initialized);
1602     return angle::Result::Continue;
1603 }
1604 
releaseImageFromStream(const Context * context)1605 angle::Result Texture::releaseImageFromStream(const Context *context)
1606 {
1607     ASSERT(mBoundStream != nullptr);
1608     ANGLE_TRY(mTexture->setImageExternal(context, mState.mType, nullptr,
1609                                          egl::Stream::GLTextureDescription()));
1610 
1611     // Set to incomplete
1612     mState.clearImageDesc(NonCubeTextureTypeToTarget(mState.mType), 0);
1613     signalDirtyStorage(InitState::Initialized);
1614     return angle::Result::Continue;
1615 }
1616 
releaseTexImageInternal(Context * context)1617 angle::Result Texture::releaseTexImageInternal(Context *context)
1618 {
1619     if (mBoundSurface)
1620     {
1621         // Notify the surface
1622         egl::Error eglErr = mBoundSurface->releaseTexImageFromTexture(context);
1623         // TODO(jmadill): Remove this once refactor is complete. http://anglebug.com/3041
1624         if (eglErr.isError())
1625         {
1626             context->handleError(GL_INVALID_OPERATION, "Error releasing tex image from texture",
1627                                  __FILE__, ANGLE_FUNCTION, __LINE__);
1628         }
1629 
1630         // Then, call the same method as from the surface
1631         ANGLE_TRY(releaseTexImageFromSurface(context));
1632     }
1633     return angle::Result::Continue;
1634 }
1635 
setEGLImageTarget(Context * context,TextureType type,egl::Image * imageTarget)1636 angle::Result Texture::setEGLImageTarget(Context *context,
1637                                          TextureType type,
1638                                          egl::Image *imageTarget)
1639 {
1640     ASSERT(type == mState.mType);
1641     ASSERT(type == TextureType::_2D || type == TextureType::External ||
1642            type == TextureType::_2DArray);
1643 
1644     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1645     ANGLE_TRY(releaseTexImageInternal(context));
1646     ANGLE_TRY(orphanImages(context));
1647 
1648     ANGLE_TRY(mTexture->setEGLImageTarget(context, type, imageTarget));
1649 
1650     setTargetImage(context, imageTarget);
1651 
1652     Extents size(static_cast<int>(imageTarget->getWidth()),
1653                  static_cast<int>(imageTarget->getHeight()), 1);
1654 
1655     auto initState = imageTarget->sourceInitState();
1656 
1657     mState.clearImageDescs();
1658     mState.setImageDesc(NonCubeTextureTypeToTarget(type), 0,
1659                         ImageDesc(size, imageTarget->getFormat(), initState));
1660     signalDirtyStorage(initState);
1661 
1662     return angle::Result::Continue;
1663 }
1664 
getAttachmentSize(const ImageIndex & imageIndex) const1665 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1666 {
1667     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1668     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1669     // one that belongs to the first face of the cube map.
1670     if (imageIndex.isEntireLevelCubeMap())
1671     {
1672         // A cube map texture is cube complete if the following conditions all hold true:
1673         // - The levelbase arrays of each of the six texture images making up the cube map have
1674         //   identical, positive, and square dimensions.
1675         if (!mState.isCubeComplete())
1676         {
1677             return Extents();
1678         }
1679     }
1680 
1681     return mState.getImageDesc(imageIndex).size;
1682 }
1683 
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1684 Format Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1685 {
1686     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1687     // we only allow querying ImageDesc on a complete cube map, and this ImageDesc is exactly the
1688     // one that belongs to the first face of the cube map.
1689     if (imageIndex.isEntireLevelCubeMap())
1690     {
1691         // A cube map texture is cube complete if the following conditions all hold true:
1692         // - The levelbase arrays were each specified with the same effective internal format.
1693         if (!mState.isCubeComplete())
1694         {
1695             return Format::Invalid();
1696         }
1697     }
1698     return mState.getImageDesc(imageIndex).format;
1699 }
1700 
getAttachmentSamples(const ImageIndex & imageIndex) const1701 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1702 {
1703     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1704     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1705     if (imageIndex.isEntireLevelCubeMap())
1706     {
1707         return 0;
1708     }
1709 
1710     return getSamples(imageIndex.getTarget(), imageIndex.getLevelIndex());
1711 }
1712 
isRenderable(const Context * context,GLenum binding,const ImageIndex & imageIndex) const1713 bool Texture::isRenderable(const Context *context,
1714                            GLenum binding,
1715                            const ImageIndex &imageIndex) const
1716 {
1717     if (isEGLImageTarget())
1718     {
1719         return ImageSibling::isRenderable(context, binding, imageIndex);
1720     }
1721     return getAttachmentFormat(binding, imageIndex)
1722         .info->textureAttachmentSupport(context->getClientVersion(), context->getExtensions());
1723 }
1724 
getAttachmentFixedSampleLocations(const ImageIndex & imageIndex) const1725 bool Texture::getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const
1726 {
1727     // We do not allow querying TextureTarget by an ImageIndex that represents an entire level of a
1728     // cube map (See comments in function TextureTypeToTarget() in ImageIndex.cpp).
1729     if (imageIndex.isEntireLevelCubeMap())
1730     {
1731         return true;
1732     }
1733 
1734     // ES3.1 (section 9.4) requires that the value of TEXTURE_FIXED_SAMPLE_LOCATIONS should be
1735     // the same for all attached textures.
1736     return getFixedSampleLocations(imageIndex.getTarget(), imageIndex.getLevelIndex());
1737 }
1738 
setBorderColor(const Context * context,const ColorGeneric & color)1739 void Texture::setBorderColor(const Context *context, const ColorGeneric &color)
1740 {
1741     mState.mSamplerState.setBorderColor(color);
1742     signalDirtyState(DIRTY_BIT_BORDER_COLOR);
1743 }
1744 
getBorderColor() const1745 const ColorGeneric &Texture::getBorderColor() const
1746 {
1747     return mState.mSamplerState.getBorderColor();
1748 }
1749 
setCrop(const Rectangle & rect)1750 void Texture::setCrop(const Rectangle &rect)
1751 {
1752     mState.setCrop(rect);
1753 }
1754 
getCrop() const1755 const Rectangle &Texture::getCrop() const
1756 {
1757     return mState.getCrop();
1758 }
1759 
setGenerateMipmapHint(GLenum hint)1760 void Texture::setGenerateMipmapHint(GLenum hint)
1761 {
1762     mState.setGenerateMipmapHint(hint);
1763 }
1764 
getGenerateMipmapHint() const1765 GLenum Texture::getGenerateMipmapHint() const
1766 {
1767     return mState.getGenerateMipmapHint();
1768 }
1769 
onAttach(const Context * context)1770 void Texture::onAttach(const Context *context)
1771 {
1772     addRef();
1773 }
1774 
onDetach(const Context * context)1775 void Texture::onDetach(const Context *context)
1776 {
1777     release(context);
1778 }
1779 
getId() const1780 GLuint Texture::getId() const
1781 {
1782     return id().value;
1783 }
1784 
getNativeID() const1785 GLuint Texture::getNativeID() const
1786 {
1787     return mTexture->getNativeID();
1788 }
1789 
syncState(const Context * context)1790 angle::Result Texture::syncState(const Context *context)
1791 {
1792     ASSERT(hasAnyDirtyBit());
1793     ANGLE_TRY(mTexture->syncState(context, mDirtyBits));
1794     mDirtyBits.reset();
1795     return angle::Result::Continue;
1796 }
1797 
getAttachmentImpl() const1798 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1799 {
1800     return mTexture;
1801 }
1802 
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1803 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1804 {
1805     const auto &samplerState =
1806         optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1807     const auto &contextState = context->getState();
1808 
1809     if (contextState.getContextID() != mCompletenessCache.context ||
1810         !mCompletenessCache.samplerState.sameCompleteness(samplerState))
1811     {
1812         mCompletenessCache.context      = context->getState().getContextID();
1813         mCompletenessCache.samplerState = samplerState;
1814         mCompletenessCache.samplerComplete =
1815             mState.computeSamplerCompleteness(samplerState, contextState);
1816     }
1817 
1818     return mCompletenessCache.samplerComplete;
1819 }
1820 
SamplerCompletenessCache()1821 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1822     : context(0), samplerState(), samplerComplete(false)
1823 {}
1824 
invalidateCompletenessCache() const1825 void Texture::invalidateCompletenessCache() const
1826 {
1827     mCompletenessCache.context = 0;
1828 }
1829 
ensureInitialized(const Context * context)1830 angle::Result Texture::ensureInitialized(const Context *context)
1831 {
1832     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1833     {
1834         return angle::Result::Continue;
1835     }
1836 
1837     bool anyDirty = false;
1838 
1839     ImageIndexIterator it =
1840         ImageIndexIterator::MakeGeneric(mState.mType, 0, IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1,
1841                                         ImageIndex::kEntireLevel, ImageIndex::kEntireLevel);
1842     while (it.hasNext())
1843     {
1844         const ImageIndex index = it.next();
1845         ImageDesc &desc =
1846             mState.mImageDescs[GetImageDescIndex(index.getTarget(), index.getLevelIndex())];
1847         if (desc.initState == InitState::MayNeedInit && !desc.size.empty())
1848         {
1849             ASSERT(mState.mInitState == InitState::MayNeedInit);
1850             ANGLE_TRY(initializeContents(context, index));
1851             desc.initState = InitState::Initialized;
1852             anyDirty       = true;
1853         }
1854     }
1855     if (anyDirty)
1856     {
1857         signalDirtyStorage(InitState::Initialized);
1858     }
1859     mState.mInitState = InitState::Initialized;
1860 
1861     return angle::Result::Continue;
1862 }
1863 
initState(const ImageIndex & imageIndex) const1864 InitState Texture::initState(const ImageIndex &imageIndex) const
1865 {
1866     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1867     // we need to check all the related ImageDescs.
1868     if (imageIndex.isEntireLevelCubeMap())
1869     {
1870         const GLint levelIndex = imageIndex.getLevelIndex();
1871         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1872         {
1873             if (mState.getImageDesc(cubeFaceTarget, levelIndex).initState == InitState::MayNeedInit)
1874             {
1875                 return InitState::MayNeedInit;
1876             }
1877         }
1878         return InitState::Initialized;
1879     }
1880 
1881     return mState.getImageDesc(imageIndex).initState;
1882 }
1883 
setInitState(const ImageIndex & imageIndex,InitState initState)1884 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1885 {
1886     // As an ImageIndex that represents an entire level of a cube map corresponds to 6 ImageDescs,
1887     // we need to update all the related ImageDescs.
1888     if (imageIndex.isEntireLevelCubeMap())
1889     {
1890         const GLint levelIndex = imageIndex.getLevelIndex();
1891         for (TextureTarget cubeFaceTarget : AllCubeFaceTextureTargets())
1892         {
1893             setInitState(ImageIndex::MakeCubeMapFace(cubeFaceTarget, levelIndex), initState);
1894         }
1895     }
1896     else
1897     {
1898         ImageDesc newDesc = mState.getImageDesc(imageIndex);
1899         newDesc.initState = initState;
1900         mState.setImageDesc(imageIndex.getTarget(), imageIndex.getLevelIndex(), newDesc);
1901     }
1902 }
1903 
doesSubImageNeedInit(const Context * context,const ImageIndex & imageIndex,const Box & area) const1904 bool Texture::doesSubImageNeedInit(const Context *context,
1905                                    const ImageIndex &imageIndex,
1906                                    const Box &area) const
1907 {
1908     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1909     {
1910         return false;
1911     }
1912 
1913     // Pre-initialize the texture contents if necessary.
1914     const ImageDesc &desc = mState.getImageDesc(imageIndex);
1915     if (desc.initState != InitState::MayNeedInit)
1916     {
1917         return false;
1918     }
1919 
1920     ASSERT(mState.mInitState == InitState::MayNeedInit);
1921     bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1922                             area.width == desc.size.width && area.height == desc.size.height &&
1923                             area.depth == desc.size.depth;
1924     return !coversWholeImage;
1925 }
1926 
ensureSubImageInitialized(const Context * context,const ImageIndex & imageIndex,const Box & area)1927 angle::Result Texture::ensureSubImageInitialized(const Context *context,
1928                                                  const ImageIndex &imageIndex,
1929                                                  const Box &area)
1930 {
1931     if (doesSubImageNeedInit(context, imageIndex, area))
1932     {
1933         // NOTE: do not optimize this to only initialize the passed area of the texture, or the
1934         // initialization logic in copySubImage will be incorrect.
1935         ANGLE_TRY(initializeContents(context, imageIndex));
1936     }
1937     setInitState(imageIndex, InitState::Initialized);
1938     return angle::Result::Continue;
1939 }
1940 
handleMipmapGenerationHint(Context * context,int level)1941 angle::Result Texture::handleMipmapGenerationHint(Context *context, int level)
1942 {
1943     if (getGenerateMipmapHint() == GL_TRUE && level == 0)
1944     {
1945         ANGLE_TRY(generateMipmap(context));
1946     }
1947 
1948     return angle::Result::Continue;
1949 }
1950 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)1951 void Texture::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
1952 {
1953     switch (message)
1954     {
1955         case angle::SubjectMessage::ContentsChanged:
1956             // ContentsChange is originates from TextureStorage11::resolveAndReleaseTexture
1957             // which resolves the underlying multisampled texture if it exists and so
1958             // Texture will signal dirty storage to invalidate its own cache and the
1959             // attached framebuffer's cache.
1960             signalDirtyStorage(InitState::Initialized);
1961             break;
1962         case angle::SubjectMessage::DirtyBitsFlagged:
1963             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1964 
1965             // Notify siblings that we are dirty.
1966             if (index == rx::kTextureImageImplObserverMessageIndex)
1967             {
1968                 notifySiblings(message);
1969             }
1970             break;
1971         case angle::SubjectMessage::SubjectChanged:
1972             mState.mInitState = InitState::MayNeedInit;
1973             signalDirtyState(DIRTY_BIT_IMPLEMENTATION);
1974             onStateChange(angle::SubjectMessage::ContentsChanged);
1975 
1976             // Notify siblings that we are dirty.
1977             if (index == rx::kTextureImageImplObserverMessageIndex)
1978             {
1979                 notifySiblings(message);
1980             }
1981             break;
1982         default:
1983             UNREACHABLE();
1984             break;
1985     }
1986 }
1987 
getImplementationColorReadFormat(const Context * context) const1988 GLenum Texture::getImplementationColorReadFormat(const Context *context) const
1989 {
1990     return mTexture->getColorReadFormat(context);
1991 }
1992 
getImplementationColorReadType(const Context * context) const1993 GLenum Texture::getImplementationColorReadType(const Context *context) const
1994 {
1995     return mTexture->getColorReadType(context);
1996 }
1997 
getTexImage(const Context * context,const PixelPackState & packState,Buffer * packBuffer,TextureTarget target,GLint level,GLenum format,GLenum type,void * pixels)1998 angle::Result Texture::getTexImage(const Context *context,
1999                                    const PixelPackState &packState,
2000                                    Buffer *packBuffer,
2001                                    TextureTarget target,
2002                                    GLint level,
2003                                    GLenum format,
2004                                    GLenum type,
2005                                    void *pixels)
2006 {
2007     if (hasAnyDirtyBit())
2008     {
2009         ANGLE_TRY(syncState(context));
2010     }
2011 
2012     return mTexture->getTexImage(context, packState, packBuffer, target, level, format, type,
2013                                  pixels);
2014 }
2015 
onBindAsImageTexture(ContextID contextID)2016 void Texture::onBindAsImageTexture(ContextID contextID)
2017 {
2018     ContextBindingCount &bindingCount = mState.getBindingCount(contextID);
2019 
2020     ASSERT(bindingCount.imageBindingCount < std::numeric_limits<uint32_t>::max());
2021     mState.getBindingCount(contextID).imageBindingCount++;
2022     if (bindingCount.imageBindingCount == 1)
2023     {
2024         mDirtyBits.set(DIRTY_BIT_BOUND_AS_IMAGE);
2025     }
2026 }
2027 
2028 }  // namespace gl
2029