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