• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // Texture.h: Defines the gl::Texture class [OpenGL ES 2.0.24] section 3.7 page 63.
8 
9 #ifndef LIBANGLE_TEXTURE_H_
10 #define LIBANGLE_TEXTURE_H_
11 
12 #include <map>
13 #include <vector>
14 
15 #include "angle_gl.h"
16 #include "common/Optional.h"
17 #include "common/debug.h"
18 #include "common/utilities.h"
19 #include "libANGLE/Caps.h"
20 #include "libANGLE/Constants.h"
21 #include "libANGLE/Debug.h"
22 #include "libANGLE/Error.h"
23 #include "libANGLE/FramebufferAttachment.h"
24 #include "libANGLE/Image.h"
25 #include "libANGLE/Observer.h"
26 #include "libANGLE/Stream.h"
27 #include "libANGLE/angletypes.h"
28 #include "libANGLE/formatutils.h"
29 
30 namespace egl
31 {
32 class Surface;
33 class Stream;
34 }  // namespace egl
35 
36 namespace rx
37 {
38 class GLImplFactory;
39 class TextureImpl;
40 class TextureGL;
41 }  // namespace rx
42 
43 namespace gl
44 {
45 class Framebuffer;
46 class MemoryObject;
47 class Sampler;
48 class State;
49 class Texture;
50 
51 constexpr GLuint kInitialMaxLevel = 1000;
52 
53 bool IsMipmapFiltered(GLenum minFilterMode);
54 
55 // Convert a given filter mode to nearest filtering.
56 GLenum ConvertToNearestFilterMode(GLenum filterMode);
57 
58 // Convert a given filter mode to nearest mip filtering.
59 GLenum ConvertToNearestMipFilterMode(GLenum filterMode);
60 
61 struct ImageDesc final
62 {
63     ImageDesc();
64     ImageDesc(const Extents &size, const Format &format, const InitState initState);
65     ImageDesc(const Extents &size,
66               const Format &format,
67               const GLsizei samples,
68               const bool fixedSampleLocations,
69               const InitState initState);
70 
71     ImageDesc(const ImageDesc &other) = default;
72     ImageDesc &operator=(const ImageDesc &other) = default;
73 
74     GLint getMemorySize() const;
75 
76     Extents size;
77     Format format;
78     GLsizei samples;
79     bool fixedSampleLocations;
80 
81     // Needed for robust resource initialization.
82     InitState initState;
83 };
84 
85 struct SwizzleState final
86 {
87     SwizzleState();
88     SwizzleState(GLenum red, GLenum green, GLenum blue, GLenum alpha);
89     SwizzleState(const SwizzleState &other) = default;
90     SwizzleState &operator=(const SwizzleState &other) = default;
91 
92     bool swizzleRequired() const;
93 
94     bool operator==(const SwizzleState &other) const;
95     bool operator!=(const SwizzleState &other) const;
96 
97     GLenum swizzleRed;
98     GLenum swizzleGreen;
99     GLenum swizzleBlue;
100     GLenum swizzleAlpha;
101 };
102 
103 // State from Table 6.9 (state per texture object) in the OpenGL ES 3.0.2 spec.
104 class TextureState final : private angle::NonCopyable
105 {
106   public:
107     TextureState(TextureType type);
108     ~TextureState();
109 
110     bool swizzleRequired() const;
111     GLuint getEffectiveBaseLevel() const;
112     GLuint getEffectiveMaxLevel() const;
113 
114     // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10.
115     GLuint getMipmapMaxLevel() const;
116 
117     // Returns true if base level changed.
118     bool setBaseLevel(GLuint baseLevel);
getBaseLevel()119     GLuint getBaseLevel() const { return mBaseLevel; }
120     bool setMaxLevel(GLuint maxLevel);
getMaxLevel()121     GLuint getMaxLevel() const { return mMaxLevel; }
122 
123     bool isCubeComplete() const;
124 
compatibleWithSamplerFormatForWebGL(SamplerFormat format,const SamplerState & samplerState)125     ANGLE_INLINE bool compatibleWithSamplerFormatForWebGL(SamplerFormat format,
126                                                           const SamplerState &samplerState) const
127     {
128         if (!mCachedSamplerFormatValid ||
129             mCachedSamplerCompareMode != samplerState.getCompareMode())
130         {
131             mCachedSamplerFormat      = computeRequiredSamplerFormat(samplerState);
132             mCachedSamplerCompareMode = samplerState.getCompareMode();
133             mCachedSamplerFormatValid = true;
134         }
135         // Incomplete textures are compatible with any sampler format.
136         return mCachedSamplerFormat == SamplerFormat::InvalidEnum || format == mCachedSamplerFormat;
137     }
138 
139     const ImageDesc &getImageDesc(TextureTarget target, size_t level) const;
140     const ImageDesc &getImageDesc(const ImageIndex &imageIndex) const;
141 
getType()142     TextureType getType() const { return mType; }
getSwizzleState()143     const SwizzleState &getSwizzleState() const { return mSwizzleState; }
getSamplerState()144     const SamplerState &getSamplerState() const { return mSamplerState; }
getUsage()145     GLenum getUsage() const { return mUsage; }
getDepthStencilTextureMode()146     GLenum getDepthStencilTextureMode() const { return mDepthStencilTextureMode; }
isStencilMode()147     bool isStencilMode() const { return mDepthStencilTextureMode == GL_STENCIL_INDEX; }
148 
hasBeenBoundAsImage()149     bool hasBeenBoundAsImage() const { return mHasBeenBoundAsImage; }
150 
getSRGBOverride()151     gl::SrgbOverride getSRGBOverride() const { return mSrgbOverride; }
152 
153     // Returns the desc of the base level. Only valid for cube-complete/mip-complete textures.
154     const ImageDesc &getBaseLevelDesc() const;
155     const ImageDesc &getLevelZeroDesc() const;
156 
157     // GLES1 emulation: For GL_OES_draw_texture
158     void setCrop(const Rectangle &rect);
159     const Rectangle &getCrop() const;
160 
161     // GLES1 emulation: Auto-mipmap generation is a texparameter
162     void setGenerateMipmapHint(GLenum hint);
163     GLenum getGenerateMipmapHint() const;
164 
165     // Return the enabled mipmap level count.
166     GLuint getEnabledLevelCount() const;
167 
getImmutableFormat()168     bool getImmutableFormat() const { return mImmutableFormat; }
getImmutableLevels()169     GLuint getImmutableLevels() const { return mImmutableLevels; }
170 
getImageDescs()171     const std::vector<ImageDesc> &getImageDescs() const { return mImageDescs; }
172 
getInitState()173     InitState getInitState() const { return mInitState; }
174 
getBuffer()175     const OffsetBindingPointer<Buffer> &getBuffer() const { return mBuffer; }
176 
getLabel()177     const std::string &getLabel() const { return mLabel; }
178 
179   private:
180     // Texture needs access to the ImageDesc functions.
181     friend class Texture;
182     friend bool operator==(const TextureState &a, const TextureState &b);
183 
184     bool computeSamplerCompleteness(const SamplerState &samplerState, const State &state) const;
185     bool computeMipmapCompleteness() const;
186     bool computeLevelCompleteness(TextureTarget target, size_t level) const;
187     SamplerFormat computeRequiredSamplerFormat(const SamplerState &samplerState) const;
188 
189     TextureTarget getBaseImageTarget() const;
190 
191     void setImageDesc(TextureTarget target, size_t level, const ImageDesc &desc);
192     void setImageDescChain(GLuint baselevel,
193                            GLuint maxLevel,
194                            Extents baseSize,
195                            const Format &format,
196                            InitState initState);
197     void setImageDescChainMultisample(Extents baseSize,
198                                       const Format &format,
199                                       GLsizei samples,
200                                       bool fixedSampleLocations,
201                                       InitState initState);
202 
203     void clearImageDesc(TextureTarget target, size_t level);
204     void clearImageDescs();
205 
206     const TextureType mType;
207 
208     SwizzleState mSwizzleState;
209 
210     SamplerState mSamplerState;
211 
212     SrgbOverride mSrgbOverride;
213 
214     GLuint mBaseLevel;
215     GLuint mMaxLevel;
216 
217     GLenum mDepthStencilTextureMode;
218 
219     bool mHasBeenBoundAsImage;
220 
221     bool mImmutableFormat;
222     GLuint mImmutableLevels;
223 
224     // From GL_ANGLE_texture_usage
225     GLenum mUsage;
226 
227     std::vector<ImageDesc> mImageDescs;
228 
229     // GLES1 emulation: Texture crop rectangle
230     // For GL_OES_draw_texture
231     Rectangle mCropRect;
232 
233     // GLES1 emulation: Generate-mipmap hint per texture
234     GLenum mGenerateMipmapHint;
235 
236     // GL_OES_texture_buffer / GLES3.2
237     OffsetBindingPointer<Buffer> mBuffer;
238 
239     InitState mInitState;
240 
241     mutable SamplerFormat mCachedSamplerFormat;
242     mutable GLenum mCachedSamplerCompareMode;
243     mutable bool mCachedSamplerFormatValid;
244     std::string mLabel;
245 };
246 
247 bool operator==(const TextureState &a, const TextureState &b);
248 bool operator!=(const TextureState &a, const TextureState &b);
249 
250 class Texture final : public RefCountObject<TextureID>,
251                       public egl::ImageSibling,
252                       public LabeledObject
253 {
254   public:
255     Texture(rx::GLImplFactory *factory, TextureID id, TextureType type);
256     ~Texture() override;
257 
258     void onDestroy(const Context *context) override;
259 
260     void setLabel(const Context *context, const std::string &label) override;
261     const std::string &getLabel() const override;
262 
getType()263     TextureType getType() const { return mState.mType; }
264 
265     void setSwizzleRed(const Context *context, GLenum swizzleRed);
266     GLenum getSwizzleRed() const;
267 
268     void setSwizzleGreen(const Context *context, GLenum swizzleGreen);
269     GLenum getSwizzleGreen() const;
270 
271     void setSwizzleBlue(const Context *context, GLenum swizzleBlue);
272     GLenum getSwizzleBlue() const;
273 
274     void setSwizzleAlpha(const Context *context, GLenum swizzleAlpha);
275     GLenum getSwizzleAlpha() const;
276 
277     void setMinFilter(const Context *context, GLenum minFilter);
278     GLenum getMinFilter() const;
279 
280     void setMagFilter(const Context *context, GLenum magFilter);
281     GLenum getMagFilter() const;
282 
283     void setWrapS(const Context *context, GLenum wrapS);
284     GLenum getWrapS() const;
285 
286     void setWrapT(const Context *context, GLenum wrapT);
287     GLenum getWrapT() const;
288 
289     void setWrapR(const Context *context, GLenum wrapR);
290     GLenum getWrapR() const;
291 
292     void setMaxAnisotropy(const Context *context, float maxAnisotropy);
293     float getMaxAnisotropy() const;
294 
295     void setMinLod(const Context *context, GLfloat minLod);
296     GLfloat getMinLod() const;
297 
298     void setMaxLod(const Context *context, GLfloat maxLod);
299     GLfloat getMaxLod() const;
300 
301     void setCompareMode(const Context *context, GLenum compareMode);
302     GLenum getCompareMode() const;
303 
304     void setCompareFunc(const Context *context, GLenum compareFunc);
305     GLenum getCompareFunc() const;
306 
307     void setSRGBDecode(const Context *context, GLenum sRGBDecode);
308     GLenum getSRGBDecode() const;
309 
310     void setSRGBOverride(const Context *context, GLenum sRGBOverride);
311     GLenum getSRGBOverride() const;
312 
313     const SamplerState &getSamplerState() const;
314 
315     angle::Result setBaseLevel(const Context *context, GLuint baseLevel);
316     GLuint getBaseLevel() const;
317 
318     void setMaxLevel(const Context *context, GLuint maxLevel);
319     GLuint getMaxLevel() const;
320 
321     void setDepthStencilTextureMode(const Context *context, GLenum mode);
322     GLenum getDepthStencilTextureMode() const;
323 
324     bool getImmutableFormat() const;
325 
326     GLuint getImmutableLevels() const;
327 
328     void setUsage(const Context *context, GLenum usage);
329     GLenum getUsage() const;
330 
getState()331     const TextureState &getState() const { return mState; }
332 
333     void setBorderColor(const Context *context, const ColorGeneric &color);
334     const ColorGeneric &getBorderColor() const;
335 
336     angle::Result setBuffer(const Context *context, gl::Buffer *buffer, GLenum internalFormat);
337     angle::Result setBufferRange(const Context *context,
338                                  gl::Buffer *buffer,
339                                  GLenum internalFormat,
340                                  GLintptr offset,
341                                  GLsizeiptr size);
342     const OffsetBindingPointer<Buffer> &getBuffer() const;
343 
344     GLint getRequiredTextureImageUnits(const Context *context) const;
345 
346     const TextureState &getTextureState() const;
347 
348     const Extents &getExtents(TextureTarget target, size_t level) const;
349     size_t getWidth(TextureTarget target, size_t level) const;
350     size_t getHeight(TextureTarget target, size_t level) const;
351     size_t getDepth(TextureTarget target, size_t level) const;
352     GLsizei getSamples(TextureTarget target, size_t level) const;
353     bool getFixedSampleLocations(TextureTarget target, size_t level) const;
354     const Format &getFormat(TextureTarget target, size_t level) const;
355 
356     // Returns the value called "q" in the GLES 3.0.4 spec section 3.8.10.
357     GLuint getMipmapMaxLevel() const;
358 
359     bool isMipmapComplete() const;
360 
361     angle::Result setImage(Context *context,
362                            const PixelUnpackState &unpackState,
363                            Buffer *unpackBuffer,
364                            TextureTarget target,
365                            GLint level,
366                            GLenum internalFormat,
367                            const Extents &size,
368                            GLenum format,
369                            GLenum type,
370                            const uint8_t *pixels);
371     angle::Result setSubImage(Context *context,
372                               const PixelUnpackState &unpackState,
373                               Buffer *unpackBuffer,
374                               TextureTarget target,
375                               GLint level,
376                               const Box &area,
377                               GLenum format,
378                               GLenum type,
379                               const uint8_t *pixels);
380 
381     angle::Result setCompressedImage(Context *context,
382                                      const PixelUnpackState &unpackState,
383                                      TextureTarget target,
384                                      GLint level,
385                                      GLenum internalFormat,
386                                      const Extents &size,
387                                      size_t imageSize,
388                                      const uint8_t *pixels);
389     angle::Result setCompressedSubImage(const Context *context,
390                                         const PixelUnpackState &unpackState,
391                                         TextureTarget target,
392                                         GLint level,
393                                         const Box &area,
394                                         GLenum format,
395                                         size_t imageSize,
396                                         const uint8_t *pixels);
397 
398     angle::Result copyImage(Context *context,
399                             TextureTarget target,
400                             GLint level,
401                             const Rectangle &sourceArea,
402                             GLenum internalFormat,
403                             Framebuffer *source);
404     angle::Result copySubImage(Context *context,
405                                const ImageIndex &index,
406                                const Offset &destOffset,
407                                const Rectangle &sourceArea,
408                                Framebuffer *source);
409 
410     angle::Result copyRenderbufferSubData(Context *context,
411                                           const gl::Renderbuffer *srcBuffer,
412                                           GLint srcLevel,
413                                           GLint srcX,
414                                           GLint srcY,
415                                           GLint srcZ,
416                                           GLint dstLevel,
417                                           GLint dstX,
418                                           GLint dstY,
419                                           GLint dstZ,
420                                           GLsizei srcWidth,
421                                           GLsizei srcHeight,
422                                           GLsizei srcDepth);
423 
424     angle::Result copyTextureSubData(Context *context,
425                                      const gl::Texture *srcTexture,
426                                      GLint srcLevel,
427                                      GLint srcX,
428                                      GLint srcY,
429                                      GLint srcZ,
430                                      GLint dstLevel,
431                                      GLint dstX,
432                                      GLint dstY,
433                                      GLint dstZ,
434                                      GLsizei srcWidth,
435                                      GLsizei srcHeight,
436                                      GLsizei srcDepth);
437 
438     angle::Result copyTexture(Context *context,
439                               TextureTarget target,
440                               GLint level,
441                               GLenum internalFormat,
442                               GLenum type,
443                               GLint sourceLevel,
444                               bool unpackFlipY,
445                               bool unpackPremultiplyAlpha,
446                               bool unpackUnmultiplyAlpha,
447                               Texture *source);
448     angle::Result copySubTexture(const Context *context,
449                                  TextureTarget target,
450                                  GLint level,
451                                  const Offset &destOffset,
452                                  GLint sourceLevel,
453                                  const Box &sourceBox,
454                                  bool unpackFlipY,
455                                  bool unpackPremultiplyAlpha,
456                                  bool unpackUnmultiplyAlpha,
457                                  Texture *source);
458     angle::Result copyCompressedTexture(Context *context, const Texture *source);
459 
460     angle::Result setStorage(Context *context,
461                              TextureType type,
462                              GLsizei levels,
463                              GLenum internalFormat,
464                              const Extents &size);
465 
466     angle::Result setStorageMultisample(Context *context,
467                                         TextureType type,
468                                         GLsizei samplesIn,
469                                         GLint internalformat,
470                                         const Extents &size,
471                                         bool fixedSampleLocations);
472 
473     angle::Result setStorageExternalMemory(Context *context,
474                                            TextureType type,
475                                            GLsizei levels,
476                                            GLenum internalFormat,
477                                            const Extents &size,
478                                            MemoryObject *memoryObject,
479                                            GLuint64 offset,
480                                            GLbitfield createFlags,
481                                            GLbitfield usageFlags);
482 
483     angle::Result setImageExternal(Context *context,
484                                    TextureTarget target,
485                                    GLint level,
486                                    GLenum internalFormat,
487                                    const Extents &size,
488                                    GLenum format,
489                                    GLenum type);
490 
491     angle::Result setEGLImageTarget(Context *context, TextureType type, egl::Image *imageTarget);
492 
493     angle::Result generateMipmap(Context *context);
494 
495     void onBindAsImageTexture();
496 
497     egl::Surface *getBoundSurface() const;
498     egl::Stream *getBoundStream() const;
499 
500     GLint getMemorySize() const;
501     GLint getLevelMemorySize(TextureTarget target, GLint level) const;
502 
503     void signalDirtyStorage(InitState initState);
504 
505     bool isSamplerComplete(const Context *context, const Sampler *optionalSampler);
506 
507     GLenum getImplementationColorReadFormat(const Context *context) const;
508     GLenum getImplementationColorReadType(const Context *context) const;
509 
510     // We pass the pack buffer and state explicitly so they can be overridden during capture.
511     angle::Result getTexImage(const Context *context,
512                               const PixelPackState &packState,
513                               Buffer *packBuffer,
514                               TextureTarget target,
515                               GLint level,
516                               GLenum format,
517                               GLenum type,
518                               void *pixels);
519 
getImplementation()520     rx::TextureImpl *getImplementation() const { return mTexture; }
521 
522     // FramebufferAttachmentObject implementation
523     Extents getAttachmentSize(const ImageIndex &imageIndex) const override;
524     Format getAttachmentFormat(GLenum binding, const ImageIndex &imageIndex) const override;
525     GLsizei getAttachmentSamples(const ImageIndex &imageIndex) const override;
526     bool isRenderable(const Context *context,
527                       GLenum binding,
528                       const ImageIndex &imageIndex) const override;
529 
530     bool getAttachmentFixedSampleLocations(const ImageIndex &imageIndex) const;
531 
532     // GLES1 emulation
533     void setCrop(const Rectangle &rect);
534     const Rectangle &getCrop() const;
535     void setGenerateMipmapHint(GLenum generate);
536     GLenum getGenerateMipmapHint() const;
537 
538     void onAttach(const Context *context, rx::Serial framebufferSerial) override;
539     void onDetach(const Context *context, rx::Serial framebufferSerial) override;
540 
541     // Used specifically for FramebufferAttachmentObject.
542     GLuint getId() const override;
543 
544     GLuint getNativeID() const;
545 
546     // Needed for robust resource init.
547     angle::Result ensureInitialized(const Context *context);
548     InitState initState(const ImageIndex &imageIndex) const override;
initState()549     InitState initState() const { return mState.mInitState; }
550     void setInitState(const ImageIndex &imageIndex, InitState initState) override;
551     void setInitState(InitState initState);
552 
isBoundToFramebuffer(rx::Serial framebufferSerial)553     bool isBoundToFramebuffer(rx::Serial framebufferSerial) const
554     {
555         for (size_t index = 0; index < mBoundFramebufferSerials.size(); ++index)
556         {
557             if (mBoundFramebufferSerials[index] == framebufferSerial)
558                 return true;
559         }
560 
561         return false;
562     }
563 
isDepthOrStencil()564     bool isDepthOrStencil() const
565     {
566         return mState.getBaseLevelDesc().format.info->isDepthOrStencil();
567     }
568 
569     enum DirtyBitType
570     {
571         // Sampler state
572         DIRTY_BIT_MIN_FILTER,
573         DIRTY_BIT_MAG_FILTER,
574         DIRTY_BIT_WRAP_S,
575         DIRTY_BIT_WRAP_T,
576         DIRTY_BIT_WRAP_R,
577         DIRTY_BIT_MAX_ANISOTROPY,
578         DIRTY_BIT_MIN_LOD,
579         DIRTY_BIT_MAX_LOD,
580         DIRTY_BIT_COMPARE_MODE,
581         DIRTY_BIT_COMPARE_FUNC,
582         DIRTY_BIT_SRGB_DECODE,
583         DIRTY_BIT_SRGB_OVERRIDE,
584         DIRTY_BIT_BORDER_COLOR,
585 
586         // Texture state
587         DIRTY_BIT_SWIZZLE_RED,
588         DIRTY_BIT_SWIZZLE_GREEN,
589         DIRTY_BIT_SWIZZLE_BLUE,
590         DIRTY_BIT_SWIZZLE_ALPHA,
591         DIRTY_BIT_BASE_LEVEL,
592         DIRTY_BIT_MAX_LEVEL,
593         DIRTY_BIT_DEPTH_STENCIL_TEXTURE_MODE,
594 
595         // Image state
596         DIRTY_BIT_BOUND_AS_IMAGE,
597 
598         // Misc
599         DIRTY_BIT_LABEL,
600         DIRTY_BIT_USAGE,
601         DIRTY_BIT_IMPLEMENTATION,
602 
603         DIRTY_BIT_COUNT,
604     };
605     using DirtyBits = angle::BitSet<DIRTY_BIT_COUNT>;
606 
607     angle::Result syncState(const Context *context, Command source);
hasAnyDirtyBit()608     bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
609 
610     // ObserverInterface implementation.
611     void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override;
612 
613   private:
614     rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override;
615 
616     // ANGLE-only method, used internally
617     friend class egl::Surface;
618     angle::Result bindTexImageFromSurface(Context *context, egl::Surface *surface);
619     angle::Result releaseTexImageFromSurface(const Context *context);
620 
621     // ANGLE-only methods, used internally
622     friend class egl::Stream;
623     void bindStream(egl::Stream *stream);
624     void releaseStream();
625     angle::Result acquireImageFromStream(const Context *context,
626                                          const egl::Stream::GLTextureDescription &desc);
627     angle::Result releaseImageFromStream(const Context *context);
628 
629     void invalidateCompletenessCache() const;
630     angle::Result releaseTexImageInternal(Context *context);
631 
632     bool doesSubImageNeedInit(const Context *context,
633                               const ImageIndex &imageIndex,
634                               const Box &area) const;
635     angle::Result ensureSubImageInitialized(const Context *context,
636                                             const ImageIndex &imageIndex,
637                                             const Box &area);
638 
639     angle::Result handleMipmapGenerationHint(Context *context, int level);
640 
641     void signalDirtyState(size_t dirtyBit);
642 
643     TextureState mState;
644     DirtyBits mDirtyBits;
645     rx::TextureImpl *mTexture;
646     angle::ObserverBinding mImplObserver;
647     // For EXT_texture_buffer, observes buffer changes.
648     angle::ObserverBinding mBufferObserver;
649 
650     egl::Surface *mBoundSurface;
651     egl::Stream *mBoundStream;
652 
653     // We track all the serials of the Framebuffers this texture is attached to. Note that this
654     // allows duplicates because different ranges of a Texture can be bound to the same Framebuffer.
655     // For the purposes of depth-stencil loops, a simple "isBound" check works fine. For color
656     // attachment Feedback Loop checks we then need to check further to see when a Texture is bound
657     // to mulitple bindings that the bindings don't overlap.
658     static constexpr uint32_t kFastFramebufferSerialCount = 8;
659     angle::FastVector<rx::Serial, kFastFramebufferSerialCount> mBoundFramebufferSerials;
660 
661     struct SamplerCompletenessCache
662     {
663         SamplerCompletenessCache();
664 
665         // Context used to generate this cache entry
666         ContextID context;
667 
668         // All values that affect sampler completeness that are not stored within
669         // the texture itself
670         SamplerState samplerState;
671 
672         // Result of the sampler completeness with the above parameters
673         bool samplerComplete;
674     };
675 
676     mutable SamplerCompletenessCache mCompletenessCache;
677 };
678 
679 inline bool operator==(const TextureState &a, const TextureState &b)
680 {
681     return a.mSwizzleState == b.mSwizzleState && a.mSamplerState == b.mSamplerState &&
682            a.mBaseLevel == b.mBaseLevel && a.mMaxLevel == b.mMaxLevel &&
683            a.mImmutableFormat == b.mImmutableFormat && a.mImmutableLevels == b.mImmutableLevels &&
684            a.mUsage == b.mUsage;
685 }
686 
687 inline bool operator!=(const TextureState &a, const TextureState &b)
688 {
689     return !(a == b);
690 }
691 }  // namespace gl
692 
693 #endif  // LIBANGLE_TEXTURE_H_
694