1 //
2 // Copyright (c) 2002-2014 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/ContextState.h"
16 #include "libANGLE/Image.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.magFilter == GL_NEAREST &&
30             (samplerState.minFilter == GL_NEAREST ||
31              samplerState.minFilter == GL_NEAREST_MIPMAP_NEAREST));
32 }
33 
GetImageDescIndex(GLenum target,size_t level)34 size_t GetImageDescIndex(GLenum target, size_t level)
35 {
36     return IsCubeMapTextureTarget(target) ? ((level * 6) + CubeMapTextureTargetToLayerIndex(target))
37                                           : level;
38 }
39 
GetImageIndexFromDescIndex(GLenum target,size_t descIndex)40 ImageIndex GetImageIndexFromDescIndex(GLenum target, size_t descIndex)
41 {
42     if (target == GL_TEXTURE_CUBE_MAP)
43     {
44         size_t faceIndex = descIndex % 6;
45         size_t mipIndex  = descIndex / 6;
46         return ImageIndex::MakeCube(LayerIndexToCubeMapTextureTarget(faceIndex),
47                                     static_cast<GLint>(mipIndex));
48     }
49 
50     return ImageIndex::MakeGeneric(target, static_cast<GLint>(descIndex));
51 }
52 
DetermineInitState(const Context * context,const uint8_t * pixels)53 InitState DetermineInitState(const Context *context, const uint8_t *pixels)
54 {
55     // Can happen in tests.
56     if (!context || !context->isRobustResourceInitEnabled())
57         return InitState::Initialized;
58 
59     const auto &glState = context->getGLState();
60     return (pixels == nullptr && glState.getTargetBuffer(gl::BufferBinding::PixelUnpack) == nullptr)
61                ? InitState::MayNeedInit
62                : InitState::Initialized;
63 }
64 
65 }  // namespace
66 
IsMipmapFiltered(const SamplerState & samplerState)67 bool IsMipmapFiltered(const SamplerState &samplerState)
68 {
69     switch (samplerState.minFilter)
70     {
71         case GL_NEAREST:
72         case GL_LINEAR:
73             return false;
74         case GL_NEAREST_MIPMAP_NEAREST:
75         case GL_LINEAR_MIPMAP_NEAREST:
76         case GL_NEAREST_MIPMAP_LINEAR:
77         case GL_LINEAR_MIPMAP_LINEAR:
78             return true;
79         default:
80             UNREACHABLE();
81             return false;
82     }
83 }
84 
SwizzleState()85 SwizzleState::SwizzleState()
86     : swizzleRed(GL_INVALID_INDEX),
87       swizzleGreen(GL_INVALID_INDEX),
88       swizzleBlue(GL_INVALID_INDEX),
89       swizzleAlpha(GL_INVALID_INDEX)
90 {
91 }
92 
SwizzleState(GLenum red,GLenum green,GLenum blue,GLenum alpha)93 SwizzleState::SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha)
94     : swizzleRed(red), swizzleGreen(green), swizzleBlue(blue), swizzleAlpha(alpha)
95 {
96 }
97 
swizzleRequired() const98 bool SwizzleState::swizzleRequired() const
99 {
100     return swizzleRed != GL_RED || swizzleGreen != GL_GREEN || swizzleBlue != GL_BLUE ||
101            swizzleAlpha != GL_ALPHA;
102 }
103 
operator ==(const SwizzleState & other) const104 bool SwizzleState::operator==(const SwizzleState &other) const
105 {
106     return swizzleRed == other.swizzleRed && swizzleGreen == other.swizzleGreen &&
107            swizzleBlue == other.swizzleBlue && swizzleAlpha == other.swizzleAlpha;
108 }
109 
operator !=(const SwizzleState & other) const110 bool SwizzleState::operator!=(const SwizzleState &other) const
111 {
112     return !(*this == other);
113 }
114 
TextureState(GLenum target)115 TextureState::TextureState(GLenum target)
116     : mTarget(target),
117       mSwizzleState(GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA),
118       mSamplerState(SamplerState::CreateDefaultForTarget(target)),
119       mBaseLevel(0),
120       mMaxLevel(1000),
121       mDepthStencilTextureMode(GL_DEPTH_COMPONENT),
122       mImmutableFormat(false),
123       mImmutableLevels(0),
124       mUsage(GL_NONE),
125       mImageDescs((IMPLEMENTATION_MAX_TEXTURE_LEVELS + 1) *
126                   (target == GL_TEXTURE_CUBE_MAP ? 6 : 1)),
127       mInitState(InitState::MayNeedInit)
128 {
129 }
130 
~TextureState()131 TextureState::~TextureState()
132 {
133 }
134 
swizzleRequired() const135 bool TextureState::swizzleRequired() const
136 {
137     return mSwizzleState.swizzleRequired();
138 }
139 
getEffectiveBaseLevel() const140 GLuint TextureState::getEffectiveBaseLevel() const
141 {
142     if (mImmutableFormat)
143     {
144         // GLES 3.0.4 section 3.8.10
145         return std::min(mBaseLevel, mImmutableLevels - 1);
146     }
147     // Some classes use the effective base level to index arrays with level data. By clamping the
148     // effective base level to max levels these arrays need just one extra item to store properties
149     // that should be returned for all out-of-range base level values, instead of needing special
150     // handling for out-of-range base levels.
151     return std::min(mBaseLevel, static_cast<GLuint>(IMPLEMENTATION_MAX_TEXTURE_LEVELS));
152 }
153 
getEffectiveMaxLevel() const154 GLuint TextureState::getEffectiveMaxLevel() const
155 {
156     if (mImmutableFormat)
157     {
158         // GLES 3.0.4 section 3.8.10
159         GLuint clampedMaxLevel = std::max(mMaxLevel, getEffectiveBaseLevel());
160         clampedMaxLevel        = std::min(clampedMaxLevel, mImmutableLevels - 1);
161         return clampedMaxLevel;
162     }
163     return mMaxLevel;
164 }
165 
getMipmapMaxLevel() const166 GLuint TextureState::getMipmapMaxLevel() const
167 {
168     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
169     GLuint expectedMipLevels       = 0;
170     if (mTarget == GL_TEXTURE_3D)
171     {
172         const int maxDim = std::max(std::max(baseImageDesc.size.width, baseImageDesc.size.height),
173                                     baseImageDesc.size.depth);
174         expectedMipLevels = static_cast<GLuint>(log2(maxDim));
175     }
176     else
177     {
178         expectedMipLevels = static_cast<GLuint>(
179             log2(std::max(baseImageDesc.size.width, baseImageDesc.size.height)));
180     }
181 
182     return std::min<GLuint>(getEffectiveBaseLevel() + expectedMipLevels, getEffectiveMaxLevel());
183 }
184 
setBaseLevel(GLuint baseLevel)185 bool TextureState::setBaseLevel(GLuint baseLevel)
186 {
187     if (mBaseLevel != baseLevel)
188     {
189         mBaseLevel = baseLevel;
190         return true;
191     }
192     return false;
193 }
194 
setMaxLevel(GLuint maxLevel)195 bool TextureState::setMaxLevel(GLuint maxLevel)
196 {
197     if (mMaxLevel != maxLevel)
198     {
199         mMaxLevel = maxLevel;
200         return true;
201     }
202 
203     return false;
204 }
205 
206 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
207 // According to [OpenGL ES 3.0.5] section 3.8.13 Texture Completeness page 160 any
208 // per-level checks begin at the base-level.
209 // For OpenGL ES2 the base level is always zero.
isCubeComplete() const210 bool TextureState::isCubeComplete() const
211 {
212     ASSERT(mTarget == GL_TEXTURE_CUBE_MAP);
213 
214     const ImageDesc &baseImageDesc =
215         getImageDesc(FirstCubeMapTextureTarget, getEffectiveBaseLevel());
216     if (baseImageDesc.size.width == 0 || baseImageDesc.size.width != baseImageDesc.size.height)
217     {
218         return false;
219     }
220 
221     for (GLenum face = FirstCubeMapTextureTarget + 1; face <= LastCubeMapTextureTarget; face++)
222     {
223         const ImageDesc &faceImageDesc = getImageDesc(face, getEffectiveBaseLevel());
224         if (faceImageDesc.size.width != baseImageDesc.size.width ||
225             faceImageDesc.size.height != baseImageDesc.size.height ||
226             !Format::SameSized(faceImageDesc.format, baseImageDesc.format))
227         {
228             return false;
229         }
230     }
231 
232     return true;
233 }
234 
computeSamplerCompleteness(const SamplerState & samplerState,const ContextState & data) const235 bool TextureState::computeSamplerCompleteness(const SamplerState &samplerState,
236                                               const ContextState &data) const
237 {
238     if (mBaseLevel > mMaxLevel)
239     {
240         return false;
241     }
242     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
243     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
244         baseImageDesc.size.depth == 0)
245     {
246         return false;
247     }
248     // The cases where the texture is incomplete because base level is out of range should be
249     // handled by the above condition.
250     ASSERT(mBaseLevel < IMPLEMENTATION_MAX_TEXTURE_LEVELS || mImmutableFormat);
251 
252     if (mTarget == GL_TEXTURE_CUBE_MAP && baseImageDesc.size.width != baseImageDesc.size.height)
253     {
254         return false;
255     }
256 
257     // According to es 3.1 spec, texture is justified as incomplete if sized internalformat is
258     // unfilterable(table 20.11) and filter is not GL_NEAREST(8.16). The default value of minFilter
259     // is NEAREST_MIPMAP_LINEAR and magFilter is LINEAR(table 20.11,). For multismaple texture,
260     // filter state of multisample texture is ignored(11.1.3.3). So it shouldn't be judged as
261     // incomplete texture. So, we ignore filtering for multisample texture completeness here.
262     if (mTarget != GL_TEXTURE_2D_MULTISAMPLE &&
263         !baseImageDesc.format.info->filterSupport(data.getClientVersion(), data.getExtensions()) &&
264         !IsPointSampled(samplerState))
265     {
266         return false;
267     }
268     bool npotSupport = data.getExtensions().textureNPOT || data.getClientMajorVersion() >= 3;
269     if (!npotSupport)
270     {
271         if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.width)) ||
272             (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(baseImageDesc.size.height)))
273         {
274             return false;
275         }
276     }
277 
278     if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && IsMipmapFiltered(samplerState))
279     {
280         if (!npotSupport)
281         {
282             if (!isPow2(baseImageDesc.size.width) || !isPow2(baseImageDesc.size.height))
283             {
284                 return false;
285             }
286         }
287 
288         if (!computeMipmapCompleteness())
289         {
290             return false;
291         }
292     }
293     else
294     {
295         if (mTarget == GL_TEXTURE_CUBE_MAP && !isCubeComplete())
296         {
297             return false;
298         }
299     }
300 
301     // From GL_OES_EGL_image_external_essl3: If state is present in a sampler object bound to a
302     // texture unit that would have been rejected by a call to TexParameter* for the texture bound
303     // to that unit, the behavior of the implementation is as if the texture were incomplete. For
304     // example, if TEXTURE_WRAP_S or TEXTURE_WRAP_T is set to anything but CLAMP_TO_EDGE on the
305     // sampler object bound to a texture unit and the texture bound to that unit is an external
306     // texture, the texture will be considered incomplete.
307     // Sampler object state which does not affect sampling for the type of texture bound to a
308     // texture unit, such as TEXTURE_WRAP_R for an external texture, does not affect completeness.
309     if (mTarget == GL_TEXTURE_EXTERNAL_OES)
310     {
311         if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE)
312         {
313             return false;
314         }
315 
316         if (samplerState.minFilter != GL_LINEAR && samplerState.minFilter != GL_NEAREST)
317         {
318             return false;
319         }
320     }
321 
322     // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
323     // The internalformat specified for the texture arrays is a sized internal depth or
324     // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
325     // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
326     // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
327     if (mTarget != GL_TEXTURE_2D_MULTISAMPLE && baseImageDesc.format.info->depthBits > 0 &&
328         data.getClientMajorVersion() >= 3)
329     {
330         // Note: we restrict this validation to sized types. For the OES_depth_textures
331         // extension, due to some underspecification problems, we must allow linear filtering
332         // for legacy compatibility with WebGL 1.
333         // See http://crbug.com/649200
334         if (samplerState.compareMode == GL_NONE && baseImageDesc.format.info->sized)
335         {
336             if ((samplerState.minFilter != GL_NEAREST &&
337                  samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
338                 samplerState.magFilter != GL_NEAREST)
339             {
340                 return false;
341             }
342         }
343     }
344 
345     return true;
346 }
347 
computeMipmapCompleteness() const348 bool TextureState::computeMipmapCompleteness() const
349 {
350     const GLuint maxLevel = getMipmapMaxLevel();
351 
352     for (GLuint level = getEffectiveBaseLevel(); level <= maxLevel; level++)
353     {
354         if (mTarget == GL_TEXTURE_CUBE_MAP)
355         {
356             for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
357             {
358                 if (!computeLevelCompleteness(face, level))
359                 {
360                     return false;
361                 }
362             }
363         }
364         else
365         {
366             if (!computeLevelCompleteness(mTarget, level))
367             {
368                 return false;
369             }
370         }
371     }
372 
373     return true;
374 }
375 
computeLevelCompleteness(GLenum target,size_t level) const376 bool TextureState::computeLevelCompleteness(GLenum target, size_t level) const
377 {
378     ASSERT(level < IMPLEMENTATION_MAX_TEXTURE_LEVELS);
379 
380     if (mImmutableFormat)
381     {
382         return true;
383     }
384 
385     const ImageDesc &baseImageDesc = getImageDesc(getBaseImageTarget(), getEffectiveBaseLevel());
386     if (baseImageDesc.size.width == 0 || baseImageDesc.size.height == 0 ||
387         baseImageDesc.size.depth == 0)
388     {
389         return false;
390     }
391 
392     const ImageDesc &levelImageDesc = getImageDesc(target, level);
393     if (levelImageDesc.size.width == 0 || levelImageDesc.size.height == 0 ||
394         levelImageDesc.size.depth == 0)
395     {
396         return false;
397     }
398 
399     if (!Format::SameSized(levelImageDesc.format, baseImageDesc.format))
400     {
401         return false;
402     }
403 
404     ASSERT(level >= getEffectiveBaseLevel());
405     const size_t relativeLevel = level - getEffectiveBaseLevel();
406     if (levelImageDesc.size.width != std::max(1, baseImageDesc.size.width >> relativeLevel))
407     {
408         return false;
409     }
410 
411     if (levelImageDesc.size.height != std::max(1, baseImageDesc.size.height >> relativeLevel))
412     {
413         return false;
414     }
415 
416     if (mTarget == GL_TEXTURE_3D)
417     {
418         if (levelImageDesc.size.depth != std::max(1, baseImageDesc.size.depth >> relativeLevel))
419         {
420             return false;
421         }
422     }
423     else if (mTarget == GL_TEXTURE_2D_ARRAY)
424     {
425         if (levelImageDesc.size.depth != baseImageDesc.size.depth)
426         {
427             return false;
428         }
429     }
430 
431     return true;
432 }
433 
getBaseImageTarget() const434 GLenum TextureState::getBaseImageTarget() const
435 {
436     return mTarget == GL_TEXTURE_CUBE_MAP ? FirstCubeMapTextureTarget : mTarget;
437 }
438 
ImageDesc()439 ImageDesc::ImageDesc()
440     : ImageDesc(Extents(0, 0, 0), Format::Invalid(), 0, GL_TRUE, InitState::Initialized)
441 {
442 }
443 
ImageDesc(const Extents & size,const Format & format,const InitState initState)444 ImageDesc::ImageDesc(const Extents &size, const Format &format, const InitState initState)
445     : size(size), format(format), samples(0), fixedSampleLocations(GL_TRUE), initState(initState)
446 {
447 }
448 
ImageDesc(const Extents & size,const Format & format,const GLsizei samples,const bool fixedSampleLocations,const InitState initState)449 ImageDesc::ImageDesc(const Extents &size,
450                      const Format &format,
451                      const GLsizei samples,
452                      const bool fixedSampleLocations,
453                      const InitState initState)
454     : size(size),
455       format(format),
456       samples(samples),
457       fixedSampleLocations(fixedSampleLocations),
458       initState(initState)
459 {
460 }
461 
getImageDesc(GLenum target,size_t level) const462 const ImageDesc &TextureState::getImageDesc(GLenum target, size_t level) const
463 {
464     size_t descIndex = GetImageDescIndex(target, level);
465     ASSERT(descIndex < mImageDescs.size());
466     return mImageDescs[descIndex];
467 }
468 
setImageDesc(GLenum target,size_t level,const ImageDesc & desc)469 void TextureState::setImageDesc(GLenum target, size_t level, const ImageDesc &desc)
470 {
471     size_t descIndex = GetImageDescIndex(target, level);
472     ASSERT(descIndex < mImageDescs.size());
473     mImageDescs[descIndex] = desc;
474     if (desc.initState == InitState::MayNeedInit)
475     {
476         mInitState = InitState::MayNeedInit;
477     }
478 }
479 
getImageDesc(const ImageIndex & imageIndex) const480 const ImageDesc &TextureState::getImageDesc(const ImageIndex &imageIndex) const
481 {
482     return getImageDesc(imageIndex.type, imageIndex.mipIndex);
483 }
484 
setImageDescChain(GLuint baseLevel,GLuint maxLevel,Extents baseSize,const Format & format,InitState initState)485 void TextureState::setImageDescChain(GLuint baseLevel,
486                                      GLuint maxLevel,
487                                      Extents baseSize,
488                                      const Format &format,
489                                      InitState initState)
490 {
491     for (GLuint level = baseLevel; level <= maxLevel; level++)
492     {
493         int relativeLevel = (level - baseLevel);
494         Extents levelSize(std::max<int>(baseSize.width >> relativeLevel, 1),
495                           std::max<int>(baseSize.height >> relativeLevel, 1),
496                           (mTarget == GL_TEXTURE_2D_ARRAY)
497                               ? baseSize.depth
498                               : std::max<int>(baseSize.depth >> relativeLevel, 1));
499         ImageDesc levelInfo(levelSize, format, initState);
500 
501         if (mTarget == GL_TEXTURE_CUBE_MAP)
502         {
503             for (GLenum face = FirstCubeMapTextureTarget; face <= LastCubeMapTextureTarget; face++)
504             {
505                 setImageDesc(face, level, levelInfo);
506             }
507         }
508         else
509         {
510             setImageDesc(mTarget, level, levelInfo);
511         }
512     }
513 }
514 
setImageDescChainMultisample(Extents baseSize,const Format & format,GLsizei samples,bool fixedSampleLocations,InitState initState)515 void TextureState::setImageDescChainMultisample(Extents baseSize,
516                                                 const Format &format,
517                                                 GLsizei samples,
518                                                 bool fixedSampleLocations,
519                                                 InitState initState)
520 {
521     ASSERT(mTarget == GL_TEXTURE_2D_MULTISAMPLE);
522     ImageDesc levelInfo(baseSize, format, samples, fixedSampleLocations, initState);
523     setImageDesc(mTarget, 0, levelInfo);
524 }
525 
clearImageDesc(GLenum target,size_t level)526 void TextureState::clearImageDesc(GLenum target, size_t level)
527 {
528     setImageDesc(target, level, ImageDesc());
529 }
530 
clearImageDescs()531 void TextureState::clearImageDescs()
532 {
533     for (size_t descIndex = 0; descIndex < mImageDescs.size(); descIndex++)
534     {
535         mImageDescs[descIndex] = ImageDesc();
536     }
537 }
538 
Texture(rx::GLImplFactory * factory,GLuint id,GLenum target)539 Texture::Texture(rx::GLImplFactory *factory, GLuint id, GLenum target)
540     : egl::ImageSibling(id),
541       mState(target),
542       mTexture(factory->createTexture(mState)),
543       mLabel(),
544       mBoundSurface(nullptr),
545       mBoundStream(nullptr)
546 {
547 }
548 
onDestroy(const Context * context)549 Error Texture::onDestroy(const Context *context)
550 {
551     if (mBoundSurface)
552     {
553         ANGLE_TRY(mBoundSurface->releaseTexImage(context, EGL_BACK_BUFFER));
554         mBoundSurface = nullptr;
555     }
556     if (mBoundStream)
557     {
558         mBoundStream->releaseTextures();
559         mBoundStream = nullptr;
560     }
561 
562     ANGLE_TRY(orphanImages(context));
563 
564     if (mTexture)
565     {
566         ANGLE_TRY(mTexture->onDestroy(context));
567     }
568     return NoError();
569 }
570 
~Texture()571 Texture::~Texture()
572 {
573     SafeDelete(mTexture);
574 }
575 
setLabel(const std::string & label)576 void Texture::setLabel(const std::string &label)
577 {
578     mLabel = label;
579     mDirtyBits.set(DIRTY_BIT_LABEL);
580 }
581 
getLabel() const582 const std::string &Texture::getLabel() const
583 {
584     return mLabel;
585 }
586 
getTarget() const587 GLenum Texture::getTarget() const
588 {
589     return mState.mTarget;
590 }
591 
setSwizzleRed(GLenum swizzleRed)592 void Texture::setSwizzleRed(GLenum swizzleRed)
593 {
594     mState.mSwizzleState.swizzleRed = swizzleRed;
595     mDirtyBits.set(DIRTY_BIT_SWIZZLE_RED);
596 }
597 
getSwizzleRed() const598 GLenum Texture::getSwizzleRed() const
599 {
600     return mState.mSwizzleState.swizzleRed;
601 }
602 
setSwizzleGreen(GLenum swizzleGreen)603 void Texture::setSwizzleGreen(GLenum swizzleGreen)
604 {
605     mState.mSwizzleState.swizzleGreen = swizzleGreen;
606     mDirtyBits.set(DIRTY_BIT_SWIZZLE_GREEN);
607 }
608 
getSwizzleGreen() const609 GLenum Texture::getSwizzleGreen() const
610 {
611     return mState.mSwizzleState.swizzleGreen;
612 }
613 
setSwizzleBlue(GLenum swizzleBlue)614 void Texture::setSwizzleBlue(GLenum swizzleBlue)
615 {
616     mState.mSwizzleState.swizzleBlue = swizzleBlue;
617     mDirtyBits.set(DIRTY_BIT_SWIZZLE_BLUE);
618 }
619 
getSwizzleBlue() const620 GLenum Texture::getSwizzleBlue() const
621 {
622     return mState.mSwizzleState.swizzleBlue;
623 }
624 
setSwizzleAlpha(GLenum swizzleAlpha)625 void Texture::setSwizzleAlpha(GLenum swizzleAlpha)
626 {
627     mState.mSwizzleState.swizzleAlpha = swizzleAlpha;
628     mDirtyBits.set(DIRTY_BIT_SWIZZLE_ALPHA);
629 }
630 
getSwizzleAlpha() const631 GLenum Texture::getSwizzleAlpha() const
632 {
633     return mState.mSwizzleState.swizzleAlpha;
634 }
635 
setMinFilter(GLenum minFilter)636 void Texture::setMinFilter(GLenum minFilter)
637 {
638     mState.mSamplerState.minFilter = minFilter;
639     mDirtyBits.set(DIRTY_BIT_MIN_FILTER);
640 }
641 
getMinFilter() const642 GLenum Texture::getMinFilter() const
643 {
644     return mState.mSamplerState.minFilter;
645 }
646 
setMagFilter(GLenum magFilter)647 void Texture::setMagFilter(GLenum magFilter)
648 {
649     mState.mSamplerState.magFilter = magFilter;
650     mDirtyBits.set(DIRTY_BIT_MAG_FILTER);
651 }
652 
getMagFilter() const653 GLenum Texture::getMagFilter() const
654 {
655     return mState.mSamplerState.magFilter;
656 }
657 
setWrapS(GLenum wrapS)658 void Texture::setWrapS(GLenum wrapS)
659 {
660     mState.mSamplerState.wrapS = wrapS;
661     mDirtyBits.set(DIRTY_BIT_WRAP_S);
662 }
663 
getWrapS() const664 GLenum Texture::getWrapS() const
665 {
666     return mState.mSamplerState.wrapS;
667 }
668 
setWrapT(GLenum wrapT)669 void Texture::setWrapT(GLenum wrapT)
670 {
671     mState.mSamplerState.wrapT = wrapT;
672     mDirtyBits.set(DIRTY_BIT_WRAP_T);
673 }
674 
getWrapT() const675 GLenum Texture::getWrapT() const
676 {
677     return mState.mSamplerState.wrapT;
678 }
679 
setWrapR(GLenum wrapR)680 void Texture::setWrapR(GLenum wrapR)
681 {
682     mState.mSamplerState.wrapR = wrapR;
683     mDirtyBits.set(DIRTY_BIT_WRAP_R);
684 }
685 
getWrapR() const686 GLenum Texture::getWrapR() const
687 {
688     return mState.mSamplerState.wrapR;
689 }
690 
setMaxAnisotropy(float maxAnisotropy)691 void Texture::setMaxAnisotropy(float maxAnisotropy)
692 {
693     mState.mSamplerState.maxAnisotropy = maxAnisotropy;
694     mDirtyBits.set(DIRTY_BIT_MAX_ANISOTROPY);
695 }
696 
getMaxAnisotropy() const697 float Texture::getMaxAnisotropy() const
698 {
699     return mState.mSamplerState.maxAnisotropy;
700 }
701 
setMinLod(GLfloat minLod)702 void Texture::setMinLod(GLfloat minLod)
703 {
704     mState.mSamplerState.minLod = minLod;
705     mDirtyBits.set(DIRTY_BIT_MIN_LOD);
706 }
707 
getMinLod() const708 GLfloat Texture::getMinLod() const
709 {
710     return mState.mSamplerState.minLod;
711 }
712 
setMaxLod(GLfloat maxLod)713 void Texture::setMaxLod(GLfloat maxLod)
714 {
715     mState.mSamplerState.maxLod = maxLod;
716     mDirtyBits.set(DIRTY_BIT_MAX_LOD);
717 }
718 
getMaxLod() const719 GLfloat Texture::getMaxLod() const
720 {
721     return mState.mSamplerState.maxLod;
722 }
723 
setCompareMode(GLenum compareMode)724 void Texture::setCompareMode(GLenum compareMode)
725 {
726     mState.mSamplerState.compareMode = compareMode;
727     mDirtyBits.set(DIRTY_BIT_COMPARE_MODE);
728 }
729 
getCompareMode() const730 GLenum Texture::getCompareMode() const
731 {
732     return mState.mSamplerState.compareMode;
733 }
734 
setCompareFunc(GLenum compareFunc)735 void Texture::setCompareFunc(GLenum compareFunc)
736 {
737     mState.mSamplerState.compareFunc = compareFunc;
738     mDirtyBits.set(DIRTY_BIT_COMPARE_FUNC);
739 }
740 
getCompareFunc() const741 GLenum Texture::getCompareFunc() const
742 {
743     return mState.mSamplerState.compareFunc;
744 }
745 
setSRGBDecode(GLenum sRGBDecode)746 void Texture::setSRGBDecode(GLenum sRGBDecode)
747 {
748     mState.mSamplerState.sRGBDecode = sRGBDecode;
749     mDirtyBits.set(DIRTY_BIT_SRGB_DECODE);
750 }
751 
getSRGBDecode() const752 GLenum Texture::getSRGBDecode() const
753 {
754     return mState.mSamplerState.sRGBDecode;
755 }
756 
getSamplerState() const757 const SamplerState &Texture::getSamplerState() const
758 {
759     return mState.mSamplerState;
760 }
761 
setBaseLevel(const Context * context,GLuint baseLevel)762 Error Texture::setBaseLevel(const Context *context, GLuint baseLevel)
763 {
764     if (mState.setBaseLevel(baseLevel))
765     {
766         ANGLE_TRY(mTexture->setBaseLevel(context, mState.getEffectiveBaseLevel()));
767         mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
768         invalidateCompletenessCache();
769     }
770 
771     return NoError();
772 }
773 
getBaseLevel() const774 GLuint Texture::getBaseLevel() const
775 {
776     return mState.mBaseLevel;
777 }
778 
setMaxLevel(GLuint maxLevel)779 void Texture::setMaxLevel(GLuint maxLevel)
780 {
781     if (mState.setMaxLevel(maxLevel))
782     {
783         mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
784         invalidateCompletenessCache();
785     }
786 }
787 
getMaxLevel() const788 GLuint Texture::getMaxLevel() const
789 {
790     return mState.mMaxLevel;
791 }
792 
setDepthStencilTextureMode(GLenum mode)793 void Texture::setDepthStencilTextureMode(GLenum mode)
794 {
795     if (mode != mState.mDepthStencilTextureMode)
796     {
797         // Changing the mode from the default state (GL_DEPTH_COMPONENT) is not implemented yet
798         UNIMPLEMENTED();
799     }
800 
801     // TODO(geofflang): add dirty bits
802     mState.mDepthStencilTextureMode = mode;
803 }
804 
getDepthStencilTextureMode() const805 GLenum Texture::getDepthStencilTextureMode() const
806 {
807     return mState.mDepthStencilTextureMode;
808 }
809 
getImmutableFormat() const810 bool Texture::getImmutableFormat() const
811 {
812     return mState.mImmutableFormat;
813 }
814 
getImmutableLevels() const815 GLuint Texture::getImmutableLevels() const
816 {
817     return mState.mImmutableLevels;
818 }
819 
setUsage(GLenum usage)820 void Texture::setUsage(GLenum usage)
821 {
822     mState.mUsage = usage;
823     mDirtyBits.set(DIRTY_BIT_USAGE);
824 }
825 
getUsage() const826 GLenum Texture::getUsage() const
827 {
828     return mState.mUsage;
829 }
830 
getTextureState() const831 const TextureState &Texture::getTextureState() const
832 {
833     return mState;
834 }
835 
getWidth(GLenum target,size_t level) const836 size_t Texture::getWidth(GLenum target, size_t level) const
837 {
838     ASSERT(target == mState.mTarget ||
839            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
840     return mState.getImageDesc(target, level).size.width;
841 }
842 
getHeight(GLenum target,size_t level) const843 size_t Texture::getHeight(GLenum target, size_t level) const
844 {
845     ASSERT(target == mState.mTarget ||
846            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
847     return mState.getImageDesc(target, level).size.height;
848 }
849 
getDepth(GLenum target,size_t level) const850 size_t Texture::getDepth(GLenum target, size_t level) const
851 {
852     ASSERT(target == mState.mTarget ||
853            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
854     return mState.getImageDesc(target, level).size.depth;
855 }
856 
getFormat(GLenum target,size_t level) const857 const Format &Texture::getFormat(GLenum target, size_t level) const
858 {
859     ASSERT(target == mState.mTarget ||
860            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
861     return mState.getImageDesc(target, level).format;
862 }
863 
getSamples(GLenum target,size_t level) const864 GLsizei Texture::getSamples(GLenum target, size_t level) const
865 {
866     ASSERT(target == mState.mTarget ||
867            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
868     return mState.getImageDesc(target, level).samples;
869 }
870 
getFixedSampleLocations(GLenum target,size_t level) const871 bool Texture::getFixedSampleLocations(GLenum target, size_t level) const
872 {
873     ASSERT(target == mState.mTarget ||
874            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
875     return mState.getImageDesc(target, level).fixedSampleLocations;
876 }
877 
getMipmapMaxLevel() const878 GLuint Texture::getMipmapMaxLevel() const
879 {
880     return mState.getMipmapMaxLevel();
881 }
882 
isMipmapComplete() const883 bool Texture::isMipmapComplete() const
884 {
885     return mState.computeMipmapCompleteness();
886 }
887 
getBoundSurface() const888 egl::Surface *Texture::getBoundSurface() const
889 {
890     return mBoundSurface;
891 }
892 
getBoundStream() const893 egl::Stream *Texture::getBoundStream() const
894 {
895     return mBoundStream;
896 }
897 
signalDirty(InitState initState) const898 void Texture::signalDirty(InitState initState) const
899 {
900     mDirtyChannel.signal(initState);
901     invalidateCompletenessCache();
902 }
903 
setImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,GLenum internalFormat,const Extents & size,GLenum format,GLenum type,const uint8_t * pixels)904 Error Texture::setImage(const Context *context,
905                         const PixelUnpackState &unpackState,
906                         GLenum target,
907                         size_t level,
908                         GLenum internalFormat,
909                         const Extents &size,
910                         GLenum format,
911                         GLenum type,
912                         const uint8_t *pixels)
913 {
914     ASSERT(target == mState.mTarget ||
915            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
916 
917     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
918     ANGLE_TRY(releaseTexImageInternal(context));
919     ANGLE_TRY(orphanImages(context));
920 
921     ANGLE_TRY(mTexture->setImage(context, target, level, internalFormat, size, format, type,
922                                  unpackState, pixels));
923 
924     InitState initState = DetermineInitState(context, pixels);
925     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat, type), initState));
926     signalDirty(initState);
927 
928     return NoError();
929 }
930 
setSubImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,const Box & area,GLenum format,GLenum type,const uint8_t * pixels)931 Error Texture::setSubImage(const Context *context,
932                            const PixelUnpackState &unpackState,
933                            GLenum target,
934                            size_t level,
935                            const Box &area,
936                            GLenum format,
937                            GLenum type,
938                            const uint8_t *pixels)
939 {
940     ASSERT(target == mState.mTarget ||
941            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
942 
943     ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
944 
945     return mTexture->setSubImage(context, target, level, area, format, type, unpackState, pixels);
946 }
947 
setCompressedImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,GLenum internalFormat,const Extents & size,size_t imageSize,const uint8_t * pixels)948 Error Texture::setCompressedImage(const Context *context,
949                                   const PixelUnpackState &unpackState,
950                                   GLenum target,
951                                   size_t level,
952                                   GLenum internalFormat,
953                                   const Extents &size,
954                                   size_t imageSize,
955                                   const uint8_t *pixels)
956 {
957     ASSERT(target == mState.mTarget ||
958            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
959 
960     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
961     ANGLE_TRY(releaseTexImageInternal(context));
962     ANGLE_TRY(orphanImages(context));
963 
964     ANGLE_TRY(mTexture->setCompressedImage(context, target, level, internalFormat, size,
965                                            unpackState, imageSize, pixels));
966 
967     InitState initState = DetermineInitState(context, pixels);
968     mState.setImageDesc(target, level, ImageDesc(size, Format(internalFormat), initState));
969     signalDirty(initState);
970 
971     return NoError();
972 }
973 
setCompressedSubImage(const Context * context,const PixelUnpackState & unpackState,GLenum target,size_t level,const Box & area,GLenum format,size_t imageSize,const uint8_t * pixels)974 Error Texture::setCompressedSubImage(const Context *context,
975                                      const PixelUnpackState &unpackState,
976                                      GLenum target,
977                                      size_t level,
978                                      const Box &area,
979                                      GLenum format,
980                                      size_t imageSize,
981                                      const uint8_t *pixels)
982 {
983     ASSERT(target == mState.mTarget ||
984            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
985 
986     ANGLE_TRY(ensureSubImageInitialized(context, target, level, area));
987 
988     return mTexture->setCompressedSubImage(context, target, level, area, format, unpackState,
989                                            imageSize, pixels);
990 }
991 
copyImage(const Context * context,GLenum target,size_t level,const Rectangle & sourceArea,GLenum internalFormat,Framebuffer * source)992 Error Texture::copyImage(const Context *context,
993                          GLenum target,
994                          size_t level,
995                          const Rectangle &sourceArea,
996                          GLenum internalFormat,
997                          Framebuffer *source)
998 {
999     ASSERT(target == mState.mTarget ||
1000            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1001 
1002     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1003     ANGLE_TRY(releaseTexImageInternal(context));
1004     ANGLE_TRY(orphanImages(context));
1005 
1006     // Ensure source FBO is initialized.
1007     ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
1008 
1009     // Use the source FBO size as the init image area.
1010     Box destBox(0, 0, 0, sourceArea.width, sourceArea.height, 1);
1011     ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1012 
1013     ANGLE_TRY(mTexture->copyImage(context, target, level, sourceArea, internalFormat, source));
1014 
1015     const InternalFormat &internalFormatInfo =
1016         GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1017 
1018     mState.setImageDesc(target, level,
1019                         ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
1020                                   Format(internalFormatInfo), InitState::Initialized));
1021 
1022     // We need to initialize this texture only if the source attachment is not initialized.
1023     signalDirty(InitState::Initialized);
1024 
1025     return NoError();
1026 }
1027 
copySubImage(const Context * context,GLenum target,size_t level,const Offset & destOffset,const Rectangle & sourceArea,Framebuffer * source)1028 Error Texture::copySubImage(const Context *context,
1029                             GLenum target,
1030                             size_t level,
1031                             const Offset &destOffset,
1032                             const Rectangle &sourceArea,
1033                             Framebuffer *source)
1034 {
1035     ASSERT(target == mState.mTarget ||
1036            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1037 
1038     // Ensure source FBO is initialized.
1039     ANGLE_TRY(source->ensureReadAttachmentInitialized(context, GL_COLOR_BUFFER_BIT));
1040 
1041     Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1);
1042     ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1043 
1044     return mTexture->copySubImage(context, target, level, destOffset, sourceArea, source);
1045 }
1046 
copyTexture(const Context * context,GLenum target,size_t level,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1047 Error Texture::copyTexture(const Context *context,
1048                            GLenum target,
1049                            size_t level,
1050                            GLenum internalFormat,
1051                            GLenum type,
1052                            size_t sourceLevel,
1053                            bool unpackFlipY,
1054                            bool unpackPremultiplyAlpha,
1055                            bool unpackUnmultiplyAlpha,
1056                            Texture *source)
1057 {
1058     ASSERT(target == mState.mTarget ||
1059            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1060 
1061     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1062     ANGLE_TRY(releaseTexImageInternal(context));
1063     ANGLE_TRY(orphanImages(context));
1064 
1065     // Initialize source texture.
1066     // Note: we don't have a way to notify which portions of the image changed currently.
1067     ANGLE_TRY(source->ensureInitialized(context));
1068 
1069     ANGLE_TRY(mTexture->copyTexture(context, target, level, internalFormat, type, sourceLevel,
1070                                     unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1071                                     source));
1072 
1073     const auto &sourceDesc   = source->mState.getImageDesc(source->getTarget(), 0);
1074     const InternalFormat &internalFormatInfo = GetInternalFormatInfo(internalFormat, type);
1075     mState.setImageDesc(
1076         target, level,
1077         ImageDesc(sourceDesc.size, Format(internalFormatInfo), InitState::Initialized));
1078 
1079     signalDirty(InitState::Initialized);
1080 
1081     return NoError();
1082 }
1083 
copySubTexture(const Context * context,GLenum target,size_t level,const Offset & destOffset,size_t sourceLevel,const Rectangle & sourceArea,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,Texture * source)1084 Error Texture::copySubTexture(const Context *context,
1085                               GLenum target,
1086                               size_t level,
1087                               const Offset &destOffset,
1088                               size_t sourceLevel,
1089                               const Rectangle &sourceArea,
1090                               bool unpackFlipY,
1091                               bool unpackPremultiplyAlpha,
1092                               bool unpackUnmultiplyAlpha,
1093                               Texture *source)
1094 {
1095     ASSERT(target == mState.mTarget ||
1096            (mState.mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
1097 
1098     // Ensure source is initialized.
1099     ANGLE_TRY(source->ensureInitialized(context));
1100 
1101     Box destBox(destOffset.x, destOffset.y, destOffset.y, sourceArea.width, sourceArea.height, 1);
1102     ANGLE_TRY(ensureSubImageInitialized(context, target, level, destBox));
1103 
1104     return mTexture->copySubTexture(context, target, level, destOffset, sourceLevel, sourceArea,
1105                                     unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha,
1106                                     source);
1107 }
1108 
copyCompressedTexture(const Context * context,const Texture * source)1109 Error Texture::copyCompressedTexture(const Context *context, const Texture *source)
1110 {
1111     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1112     ANGLE_TRY(releaseTexImageInternal(context));
1113     ANGLE_TRY(orphanImages(context));
1114 
1115     ANGLE_TRY(mTexture->copyCompressedTexture(context, source));
1116 
1117     ASSERT(source->getTarget() != GL_TEXTURE_CUBE_MAP && getTarget() != GL_TEXTURE_CUBE_MAP);
1118     const auto &sourceDesc = source->mState.getImageDesc(source->getTarget(), 0);
1119     mState.setImageDesc(getTarget(), 0, sourceDesc);
1120 
1121     return NoError();
1122 }
1123 
setStorage(const Context * context,GLenum target,GLsizei levels,GLenum internalFormat,const Extents & size)1124 Error Texture::setStorage(const Context *context,
1125                           GLenum target,
1126                           GLsizei levels,
1127                           GLenum internalFormat,
1128                           const Extents &size)
1129 {
1130     ASSERT(target == mState.mTarget);
1131 
1132     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1133     ANGLE_TRY(releaseTexImageInternal(context));
1134     ANGLE_TRY(orphanImages(context));
1135 
1136     ANGLE_TRY(mTexture->setStorage(context, target, levels, internalFormat, size));
1137 
1138     mState.mImmutableFormat = true;
1139     mState.mImmutableLevels = static_cast<GLuint>(levels);
1140     mState.clearImageDescs();
1141     mState.setImageDescChain(0, static_cast<GLuint>(levels - 1), size, Format(internalFormat),
1142                              InitState::MayNeedInit);
1143 
1144     // Changing the texture to immutable can trigger a change in the base and max levels:
1145     // GLES 3.0.4 section 3.8.10 pg 158:
1146     // "For immutable-format textures, levelbase is clamped to the range[0;levels],levelmax is then
1147     // clamped to the range[levelbase;levels].
1148     mDirtyBits.set(DIRTY_BIT_BASE_LEVEL);
1149     mDirtyBits.set(DIRTY_BIT_MAX_LEVEL);
1150 
1151     signalDirty(InitState::MayNeedInit);
1152 
1153     return NoError();
1154 }
1155 
setStorageMultisample(const Context * context,GLenum target,GLsizei samples,GLint internalFormat,const Extents & size,bool fixedSampleLocations)1156 Error Texture::setStorageMultisample(const Context *context,
1157                                      GLenum target,
1158                                      GLsizei samples,
1159                                      GLint internalFormat,
1160                                      const Extents &size,
1161                                      bool fixedSampleLocations)
1162 {
1163     ASSERT(target == mState.mTarget);
1164 
1165     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1166     ANGLE_TRY(releaseTexImageInternal(context));
1167     ANGLE_TRY(orphanImages(context));
1168 
1169     ANGLE_TRY(mTexture->setStorageMultisample(context, target, samples, internalFormat, size,
1170                                               fixedSampleLocations));
1171 
1172     mState.mImmutableFormat = true;
1173     mState.mImmutableLevels = static_cast<GLuint>(1);
1174     mState.clearImageDescs();
1175     mState.setImageDescChainMultisample(size, Format(internalFormat), samples, fixedSampleLocations,
1176                                         InitState::MayNeedInit);
1177 
1178     signalDirty(InitState::MayNeedInit);
1179 
1180     return NoError();
1181 }
1182 
generateMipmap(const Context * context)1183 Error Texture::generateMipmap(const Context *context)
1184 {
1185     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1186     ANGLE_TRY(releaseTexImageInternal(context));
1187 
1188     // EGL_KHR_gl_image states that images are only orphaned when generating mipmaps if the texture
1189     // is not mip complete.
1190     if (!isMipmapComplete())
1191     {
1192         ANGLE_TRY(orphanImages(context));
1193     }
1194 
1195     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1196     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1197 
1198     if (maxLevel > baseLevel)
1199     {
1200         syncState();
1201         const ImageDesc &baseImageInfo =
1202             mState.getImageDesc(mState.getBaseImageTarget(), baseLevel);
1203 
1204         // Clear the base image immediately if necessary.
1205         if (context->isRobustResourceInitEnabled() &&
1206             baseImageInfo.initState == InitState::MayNeedInit)
1207         {
1208             ANGLE_TRY(initializeContents(
1209                 context, GetImageIndexFromDescIndex(mState.getBaseImageTarget(), baseLevel)));
1210         }
1211 
1212         ANGLE_TRY(mTexture->generateMipmap(context));
1213 
1214         mState.setImageDescChain(baseLevel, maxLevel, baseImageInfo.size, baseImageInfo.format,
1215                                  InitState::Initialized);
1216     }
1217 
1218     signalDirty(InitState::Initialized);
1219 
1220     return NoError();
1221 }
1222 
bindTexImageFromSurface(const Context * context,egl::Surface * surface)1223 Error Texture::bindTexImageFromSurface(const Context *context, egl::Surface *surface)
1224 {
1225     ASSERT(surface);
1226 
1227     if (mBoundSurface)
1228     {
1229         ANGLE_TRY(releaseTexImageFromSurface(context));
1230     }
1231 
1232     ANGLE_TRY(mTexture->bindTexImage(context, surface));
1233     mBoundSurface = surface;
1234 
1235     // Set the image info to the size and format of the surface
1236     ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
1237     Extents size(surface->getWidth(), surface->getHeight(), 1);
1238     ImageDesc desc(size, Format(surface->getConfig()->renderTargetFormat), InitState::Initialized);
1239     mState.setImageDesc(mState.mTarget, 0, desc);
1240     signalDirty(InitState::Initialized);
1241     return NoError();
1242 }
1243 
releaseTexImageFromSurface(const Context * context)1244 Error Texture::releaseTexImageFromSurface(const Context *context)
1245 {
1246     ASSERT(mBoundSurface);
1247     mBoundSurface = nullptr;
1248     ANGLE_TRY(mTexture->releaseTexImage(context));
1249 
1250     // Erase the image info for level 0
1251     ASSERT(mState.mTarget == GL_TEXTURE_2D || mState.mTarget == GL_TEXTURE_RECTANGLE_ANGLE);
1252     mState.clearImageDesc(mState.mTarget, 0);
1253     signalDirty(InitState::Initialized);
1254     return NoError();
1255 }
1256 
bindStream(egl::Stream * stream)1257 void Texture::bindStream(egl::Stream *stream)
1258 {
1259     ASSERT(stream);
1260 
1261     // It should not be possible to bind a texture already bound to another stream
1262     ASSERT(mBoundStream == nullptr);
1263 
1264     mBoundStream = stream;
1265 
1266     ASSERT(mState.mTarget == GL_TEXTURE_EXTERNAL_OES);
1267 }
1268 
releaseStream()1269 void Texture::releaseStream()
1270 {
1271     ASSERT(mBoundStream);
1272     mBoundStream = nullptr;
1273 }
1274 
acquireImageFromStream(const Context * context,const egl::Stream::GLTextureDescription & desc)1275 Error Texture::acquireImageFromStream(const Context *context,
1276                                       const egl::Stream::GLTextureDescription &desc)
1277 {
1278     ASSERT(mBoundStream != nullptr);
1279     ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, mBoundStream, desc));
1280 
1281     Extents size(desc.width, desc.height, 1);
1282     mState.setImageDesc(mState.mTarget, 0,
1283                         ImageDesc(size, Format(desc.internalFormat), InitState::Initialized));
1284     signalDirty(InitState::Initialized);
1285     return NoError();
1286 }
1287 
releaseImageFromStream(const Context * context)1288 Error Texture::releaseImageFromStream(const Context *context)
1289 {
1290     ASSERT(mBoundStream != nullptr);
1291     ANGLE_TRY(mTexture->setImageExternal(context, mState.mTarget, nullptr,
1292                                          egl::Stream::GLTextureDescription()));
1293 
1294     // Set to incomplete
1295     mState.clearImageDesc(mState.mTarget, 0);
1296     signalDirty(InitState::Initialized);
1297     return NoError();
1298 }
1299 
releaseTexImageInternal(const Context * context)1300 Error Texture::releaseTexImageInternal(const Context *context)
1301 {
1302     if (mBoundSurface)
1303     {
1304         // Notify the surface
1305         mBoundSurface->releaseTexImageFromTexture(context);
1306 
1307         // Then, call the same method as from the surface
1308         ANGLE_TRY(releaseTexImageFromSurface(context));
1309     }
1310     return NoError();
1311 }
1312 
setEGLImageTarget(const Context * context,GLenum target,egl::Image * imageTarget)1313 Error Texture::setEGLImageTarget(const Context *context, GLenum target, egl::Image *imageTarget)
1314 {
1315     ASSERT(target == mState.mTarget);
1316     ASSERT(target == GL_TEXTURE_2D || target == GL_TEXTURE_EXTERNAL_OES);
1317 
1318     // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
1319     ANGLE_TRY(releaseTexImageInternal(context));
1320     ANGLE_TRY(orphanImages(context));
1321 
1322     ANGLE_TRY(mTexture->setEGLImageTarget(context, target, imageTarget));
1323 
1324     setTargetImage(context, imageTarget);
1325 
1326     Extents size(static_cast<int>(imageTarget->getWidth()),
1327                  static_cast<int>(imageTarget->getHeight()), 1);
1328 
1329     auto initState = imageTarget->sourceInitState();
1330 
1331     mState.clearImageDescs();
1332     mState.setImageDesc(target, 0, ImageDesc(size, imageTarget->getFormat(), initState));
1333     signalDirty(initState);
1334 
1335     return NoError();
1336 }
1337 
getAttachmentSize(const ImageIndex & imageIndex) const1338 Extents Texture::getAttachmentSize(const ImageIndex &imageIndex) const
1339 {
1340     return mState.getImageDesc(imageIndex).size;
1341 }
1342 
getAttachmentFormat(GLenum,const ImageIndex & imageIndex) const1343 const Format &Texture::getAttachmentFormat(GLenum /*binding*/, const ImageIndex &imageIndex) const
1344 {
1345     return mState.getImageDesc(imageIndex).format;
1346 }
1347 
getAttachmentSamples(const ImageIndex & imageIndex) const1348 GLsizei Texture::getAttachmentSamples(const ImageIndex &imageIndex) const
1349 {
1350     return getSamples(imageIndex.type, 0);
1351 }
1352 
onAttach(const Context * context)1353 void Texture::onAttach(const Context *context)
1354 {
1355     addRef();
1356 }
1357 
onDetach(const Context * context)1358 void Texture::onDetach(const Context *context)
1359 {
1360     release(context);
1361 }
1362 
getId() const1363 GLuint Texture::getId() const
1364 {
1365     return id();
1366 }
1367 
syncState()1368 void Texture::syncState()
1369 {
1370     mTexture->syncState(mDirtyBits);
1371     mDirtyBits.reset();
1372 }
1373 
getAttachmentImpl() const1374 rx::FramebufferAttachmentObjectImpl *Texture::getAttachmentImpl() const
1375 {
1376     return mTexture;
1377 }
1378 
isSamplerComplete(const Context * context,const Sampler * optionalSampler)1379 bool Texture::isSamplerComplete(const Context *context, const Sampler *optionalSampler)
1380 {
1381     const auto &samplerState =
1382         optionalSampler ? optionalSampler->getSamplerState() : mState.mSamplerState;
1383     const auto &contextState = context->getContextState();
1384 
1385     if (contextState.getContextID() != mCompletenessCache.context ||
1386         mCompletenessCache.samplerState != samplerState)
1387     {
1388         mCompletenessCache.context      = context->getContextState().getContextID();
1389         mCompletenessCache.samplerState = samplerState;
1390         mCompletenessCache.samplerComplete =
1391             mState.computeSamplerCompleteness(samplerState, contextState);
1392     }
1393 
1394     return mCompletenessCache.samplerComplete;
1395 }
1396 
SamplerCompletenessCache()1397 Texture::SamplerCompletenessCache::SamplerCompletenessCache()
1398     : context(0), samplerState(), samplerComplete(false)
1399 {
1400 }
1401 
invalidateCompletenessCache() const1402 void Texture::invalidateCompletenessCache() const
1403 {
1404     mCompletenessCache.context = 0;
1405 }
1406 
ensureInitialized(const Context * context)1407 Error Texture::ensureInitialized(const Context *context)
1408 {
1409     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1410     {
1411         return NoError();
1412     }
1413 
1414     bool anyDirty = false;
1415 
1416     for (size_t descIndex = 0; descIndex < mState.mImageDescs.size(); ++descIndex)
1417     {
1418         auto &imageDesc = mState.mImageDescs[descIndex];
1419         if (imageDesc.initState == InitState::MayNeedInit)
1420         {
1421             ASSERT(mState.mInitState == InitState::MayNeedInit);
1422             const auto &imageIndex = GetImageIndexFromDescIndex(mState.mTarget, descIndex);
1423             ANGLE_TRY(initializeContents(context, imageIndex));
1424             imageDesc.initState = InitState::Initialized;
1425             anyDirty            = true;
1426         }
1427     }
1428     if (anyDirty)
1429     {
1430         signalDirty(InitState::Initialized);
1431     }
1432     mState.mInitState = InitState::Initialized;
1433 
1434     return NoError();
1435 }
1436 
initState(const ImageIndex & imageIndex) const1437 InitState Texture::initState(const ImageIndex &imageIndex) const
1438 {
1439     return mState.getImageDesc(imageIndex).initState;
1440 }
1441 
initState() const1442 InitState Texture::initState() const
1443 {
1444     return mState.mInitState;
1445 }
1446 
setInitState(const ImageIndex & imageIndex,InitState initState)1447 void Texture::setInitState(const ImageIndex &imageIndex, InitState initState)
1448 {
1449     ImageDesc newDesc = mState.getImageDesc(imageIndex);
1450     newDesc.initState = initState;
1451     mState.setImageDesc(imageIndex.type, imageIndex.mipIndex, newDesc);
1452 }
1453 
ensureSubImageInitialized(const Context * context,GLenum target,size_t level,const gl::Box & area)1454 Error Texture::ensureSubImageInitialized(const Context *context,
1455                                          GLenum target,
1456                                          size_t level,
1457                                          const gl::Box &area)
1458 {
1459     if (!context->isRobustResourceInitEnabled() || mState.mInitState == InitState::Initialized)
1460     {
1461         return NoError();
1462     }
1463 
1464     // Pre-initialize the texture contents if necessary.
1465     // TODO(jmadill): Check if area overlaps the entire texture.
1466     const auto &imageIndex = GetImageIndexFromDescIndex(target, level);
1467     const auto &desc       = mState.getImageDesc(imageIndex);
1468     if (desc.initState == InitState::MayNeedInit)
1469     {
1470         ASSERT(mState.mInitState == InitState::MayNeedInit);
1471         bool coversWholeImage = area.x == 0 && area.y == 0 && area.z == 0 &&
1472                                 area.width == desc.size.width && area.height == desc.size.height &&
1473                                 area.depth == desc.size.depth;
1474         if (!coversWholeImage)
1475         {
1476             ANGLE_TRY(initializeContents(context, imageIndex));
1477         }
1478         setInitState(imageIndex, InitState::Initialized);
1479     }
1480 
1481     return NoError();
1482 }
1483 
1484 }  // namespace gl
1485