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