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