1 // 2 // Copyright 2016 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 // TextureVk.h: 7 // Defines the class interface for TextureVk, implementing TextureImpl. 8 // 9 10 #ifndef LIBANGLE_RENDERER_VULKAN_TEXTUREVK_H_ 11 #define LIBANGLE_RENDERER_VULKAN_TEXTUREVK_H_ 12 13 #include "libANGLE/renderer/TextureImpl.h" 14 #include "libANGLE/renderer/vulkan/RenderTargetVk.h" 15 #include "libANGLE/renderer/vulkan/ResourceVk.h" 16 #include "libANGLE/renderer/vulkan/SamplerVk.h" 17 #include "libANGLE/renderer/vulkan/vk_helpers.h" 18 19 namespace rx 20 { 21 22 enum class ImageMipLevels 23 { 24 EnabledLevels = 0, 25 FullMipChain = 1, 26 27 InvalidEnum = 2, 28 }; 29 30 // vkCmdCopyBufferToImage buffer offset multiple 31 constexpr VkDeviceSize kBufferOffsetMultiple = 4; 32 33 class TextureVk : public TextureImpl, public angle::ObserverInterface 34 { 35 public: 36 TextureVk(const gl::TextureState &state, RendererVk *renderer); 37 ~TextureVk() override; 38 void onDestroy(const gl::Context *context) override; 39 40 angle::Result setImage(const gl::Context *context, 41 const gl::ImageIndex &index, 42 GLenum internalFormat, 43 const gl::Extents &size, 44 GLenum format, 45 GLenum type, 46 const gl::PixelUnpackState &unpack, 47 gl::Buffer *unpackBuffer, 48 const uint8_t *pixels) override; 49 angle::Result setSubImage(const gl::Context *context, 50 const gl::ImageIndex &index, 51 const gl::Box &area, 52 GLenum format, 53 GLenum type, 54 const gl::PixelUnpackState &unpack, 55 gl::Buffer *unpackBuffer, 56 const uint8_t *pixels) override; 57 58 angle::Result setCompressedImage(const gl::Context *context, 59 const gl::ImageIndex &index, 60 GLenum internalFormat, 61 const gl::Extents &size, 62 const gl::PixelUnpackState &unpack, 63 size_t imageSize, 64 const uint8_t *pixels) override; 65 angle::Result setCompressedSubImage(const gl::Context *context, 66 const gl::ImageIndex &index, 67 const gl::Box &area, 68 GLenum format, 69 const gl::PixelUnpackState &unpack, 70 size_t imageSize, 71 const uint8_t *pixels) override; 72 73 angle::Result copyImage(const gl::Context *context, 74 const gl::ImageIndex &index, 75 const gl::Rectangle &sourceArea, 76 GLenum internalFormat, 77 gl::Framebuffer *source) override; 78 angle::Result copySubImage(const gl::Context *context, 79 const gl::ImageIndex &index, 80 const gl::Offset &destOffset, 81 const gl::Rectangle &sourceArea, 82 gl::Framebuffer *source) override; 83 84 angle::Result copyTexture(const gl::Context *context, 85 const gl::ImageIndex &index, 86 GLenum internalFormat, 87 GLenum type, 88 GLint sourceLevelGL, 89 bool unpackFlipY, 90 bool unpackPremultiplyAlpha, 91 bool unpackUnmultiplyAlpha, 92 const gl::Texture *source) override; 93 angle::Result copySubTexture(const gl::Context *context, 94 const gl::ImageIndex &index, 95 const gl::Offset &destOffset, 96 GLint sourceLevelGL, 97 const gl::Box &sourceBox, 98 bool unpackFlipY, 99 bool unpackPremultiplyAlpha, 100 bool unpackUnmultiplyAlpha, 101 const gl::Texture *source) override; 102 103 angle::Result copyRenderbufferSubData(const gl::Context *context, 104 const gl::Renderbuffer *srcBuffer, 105 GLint srcLevel, 106 GLint srcX, 107 GLint srcY, 108 GLint srcZ, 109 GLint dstLevel, 110 GLint dstX, 111 GLint dstY, 112 GLint dstZ, 113 GLsizei srcWidth, 114 GLsizei srcHeight, 115 GLsizei srcDepth) override; 116 117 angle::Result copyTextureSubData(const gl::Context *context, 118 const gl::Texture *srcTexture, 119 GLint srcLevel, 120 GLint srcX, 121 GLint srcY, 122 GLint srcZ, 123 GLint dstLevel, 124 GLint dstX, 125 GLint dstY, 126 GLint dstZ, 127 GLsizei srcWidth, 128 GLsizei srcHeight, 129 GLsizei srcDepth) override; 130 131 angle::Result copyCompressedTexture(const gl::Context *context, 132 const gl::Texture *source) override; 133 134 angle::Result setStorage(const gl::Context *context, 135 gl::TextureType type, 136 size_t levels, 137 GLenum internalFormat, 138 const gl::Extents &size) override; 139 140 angle::Result setStorageExternalMemory(const gl::Context *context, 141 gl::TextureType type, 142 size_t levels, 143 GLenum internalFormat, 144 const gl::Extents &size, 145 gl::MemoryObject *memoryObject, 146 GLuint64 offset, 147 GLbitfield createFlags, 148 GLbitfield usageFlags, 149 const void *imageCreateInfoPNext) override; 150 151 angle::Result setEGLImageTarget(const gl::Context *context, 152 gl::TextureType type, 153 egl::Image *image) override; 154 155 angle::Result setImageExternal(const gl::Context *context, 156 gl::TextureType type, 157 egl::Stream *stream, 158 const egl::Stream::GLTextureDescription &desc) override; 159 160 angle::Result setBuffer(const gl::Context *context, GLenum internalFormat) override; 161 162 angle::Result generateMipmap(const gl::Context *context) override; 163 164 angle::Result setBaseLevel(const gl::Context *context, GLuint baseLevel) override; 165 166 angle::Result bindTexImage(const gl::Context *context, egl::Surface *surface) override; 167 angle::Result releaseTexImage(const gl::Context *context) override; 168 169 angle::Result getAttachmentRenderTarget(const gl::Context *context, 170 GLenum binding, 171 const gl::ImageIndex &imageIndex, 172 GLsizei samples, 173 FramebufferAttachmentRenderTarget **rtOut) override; 174 175 angle::Result syncState(const gl::Context *context, 176 const gl::Texture::DirtyBits &dirtyBits, 177 gl::Command source) override; 178 179 angle::Result setStorageMultisample(const gl::Context *context, 180 gl::TextureType type, 181 GLsizei samples, 182 GLint internalformat, 183 const gl::Extents &size, 184 bool fixedSampleLocations) override; 185 186 angle::Result initializeContents(const gl::Context *context, 187 const gl::ImageIndex &imageIndex) override; 188 getImage()189 const vk::ImageHelper &getImage() const 190 { 191 ASSERT(mImage && mImage->valid()); 192 return *mImage; 193 } 194 getImage()195 vk::ImageHelper &getImage() 196 { 197 ASSERT(mImage && mImage->valid()); 198 return *mImage; 199 } 200 retainImageViews(vk::ResourceUseList * resourceUseList)201 void retainImageViews(vk::ResourceUseList *resourceUseList) 202 { 203 getImageViews().retain(resourceUseList); 204 } 205 retainBufferViews(vk::ResourceUseList * resourceUseList)206 void retainBufferViews(vk::ResourceUseList *resourceUseList) 207 { 208 mBufferViews.retain(resourceUseList); 209 } 210 211 void releaseOwnershipOfImage(const gl::Context *context); 212 213 const vk::ImageView &getReadImageViewAndRecordUse(ContextVk *contextVk, 214 GLenum srgbDecode, 215 bool texelFetchStaticUse) const; 216 217 // A special view for cube maps as a 2D array, used with shaders that do texelFetch() and for 218 // seamful cube map emulation. 219 const vk::ImageView &getFetchImageViewAndRecordUse(ContextVk *contextVk, 220 GLenum srgbDecode, 221 bool texelFetchStaticUse) const; 222 223 // A special view used for texture copies that shouldn't perform swizzle. 224 const vk::ImageView &getCopyImageViewAndRecordUse(ContextVk *contextVk) const; 225 angle::Result getStorageImageView(ContextVk *contextVk, 226 const gl::ImageUnit &binding, 227 const vk::ImageView **imageViewOut); 228 getSampler()229 const vk::SamplerHelper &getSampler() const 230 { 231 ASSERT(mSampler.valid()); 232 return mSampler.get(); 233 } 234 235 angle::Result getBufferViewAndRecordUse(ContextVk *contextVk, 236 const vk::Format *imageUniformFormat, 237 bool isImage, 238 const vk::BufferView **viewOut); 239 240 // Normally, initialize the image with enabled mipmap level counts. 241 angle::Result ensureImageInitialized(ContextVk *contextVk, ImageMipLevels mipLevels); 242 243 vk::ImageOrBufferViewSubresourceSerial getImageViewSubresourceSerial( 244 const gl::SamplerState &samplerState) const; 245 vk::ImageOrBufferViewSubresourceSerial getBufferViewSerial() const; 246 overrideStagingBufferSizeForTesting(size_t initialSizeForTesting)247 void overrideStagingBufferSizeForTesting(size_t initialSizeForTesting) 248 { 249 mStagingBufferInitialSize = initialSizeForTesting; 250 } 251 252 GLenum getColorReadFormat(const gl::Context *context) override; 253 GLenum getColorReadType(const gl::Context *context) override; 254 255 angle::Result getTexImage(const gl::Context *context, 256 const gl::PixelPackState &packState, 257 gl::Buffer *packBuffer, 258 gl::TextureTarget target, 259 GLint level, 260 GLenum format, 261 GLenum type, 262 void *pixels) override; 263 264 angle::Result getCompressedTexImage(const gl::Context *context, 265 const gl::PixelPackState &packState, 266 gl::Buffer *packBuffer, 267 gl::TextureTarget target, 268 GLint level, 269 void *pixels) override; 270 hasBeenBoundAsImage()271 ANGLE_INLINE bool hasBeenBoundAsImage() const { return mState.hasBeenBoundAsImage(); } getBuffer()272 ANGLE_INLINE const gl::OffsetBindingPointer<gl::Buffer> &getBuffer() const 273 { 274 return mState.getBuffer(); 275 } 276 isSRGBOverrideEnabled()277 bool isSRGBOverrideEnabled() const 278 { 279 return mState.getSRGBOverride() != gl::SrgbOverride::Default; 280 } 281 282 angle::Result ensureMutable(ContextVk *contextVk); 283 angle::Result ensureRenderable(ContextVk *contextVk); 284 getAndResetImmutableSamplerDirtyState()285 bool getAndResetImmutableSamplerDirtyState() 286 { 287 bool isDirty = mImmutableSamplerDirty; 288 mImmutableSamplerDirty = false; 289 return isDirty; 290 } 291 292 private: 293 // Transform an image index from the frontend into one that can be used on the backing 294 // ImageHelper, taking into account mipmap or cube face offsets 295 gl::ImageIndex getNativeImageIndex(const gl::ImageIndex &inputImageIndex) const; 296 gl::LevelIndex getNativeImageLevel(gl::LevelIndex frontendLevel) const; 297 uint32_t getNativeImageLayer(uint32_t frontendLayer) const; 298 299 // Get the layer count for views. 300 uint32_t getImageViewLayerCount() const; 301 302 void releaseAndDeleteImageAndViews(ContextVk *contextVk); 303 angle::Result ensureImageAllocated(ContextVk *contextVk, const vk::Format &format); 304 void setImageHelper(ContextVk *contextVk, 305 vk::ImageHelper *imageHelper, 306 gl::TextureType imageType, 307 const vk::Format &format, 308 uint32_t imageLevelOffset, 309 uint32_t imageLayerOffset, 310 bool selfOwned); 311 void updateImageHelper(ContextVk *contextVk, size_t imageCopyBufferAlignment); getImageViews()312 vk::ImageViewHelper &getImageViews() 313 { 314 return mMultisampledImageViews[gl::RenderToTextureImageIndex::Default]; 315 } getImageViews()316 const vk::ImageViewHelper &getImageViews() const 317 { 318 return mMultisampledImageViews[gl::RenderToTextureImageIndex::Default]; 319 } 320 321 // Redefine a mip level of the texture. If the new size and format don't match the allocated 322 // image, the image may be released. When redefining a mip of a multi-level image, updates are 323 // forced to be staged, as another mip of the image may be bound to a framebuffer. For example, 324 // assume texture has two mips, and framebuffer is bound to mip 0. Redefining mip 1 to an 325 // incompatible size shouldn't affect the framebuffer, especially if the redefinition comes from 326 // something like glCopyTexSubImage2D() (which simultaneously is reading from said framebuffer, 327 // i.e. mip 0 of the texture). 328 angle::Result redefineLevel(const gl::Context *context, 329 const gl::ImageIndex &index, 330 const vk::Format &format, 331 const gl::Extents &size); 332 333 angle::Result setImageImpl(const gl::Context *context, 334 const gl::ImageIndex &index, 335 const gl::InternalFormat &formatInfo, 336 const gl::Extents &size, 337 GLenum type, 338 const gl::PixelUnpackState &unpack, 339 gl::Buffer *unpackBuffer, 340 const uint8_t *pixels); 341 angle::Result setSubImageImpl(const gl::Context *context, 342 const gl::ImageIndex &index, 343 const gl::Box &area, 344 const gl::InternalFormat &formatInfo, 345 GLenum type, 346 const gl::PixelUnpackState &unpack, 347 gl::Buffer *unpackBuffer, 348 const uint8_t *pixels, 349 const vk::Format &vkFormat); 350 351 angle::Result copyImageDataToBufferAndGetData(ContextVk *contextVk, 352 gl::LevelIndex sourceLevelGL, 353 uint32_t layerCount, 354 const gl::Box &sourceArea, 355 RenderPassClosureReason reason, 356 uint8_t **outDataPtr); 357 358 angle::Result copyBufferDataToImage(ContextVk *contextVk, 359 vk::BufferHelper *srcBuffer, 360 const gl::ImageIndex index, 361 uint32_t rowLength, 362 uint32_t imageHeight, 363 const gl::Box &sourceArea, 364 size_t offset, 365 VkImageAspectFlags aspectFlags); 366 367 // Called from syncState to prepare the image for mipmap generation. 368 void prepareForGenerateMipmap(ContextVk *contextVk); 369 370 // Generate mipmaps from level 0 into the rest of the mips. This requires the image to have 371 // STORAGE usage. 372 angle::Result generateMipmapsWithCompute(ContextVk *contextVk); 373 374 angle::Result generateMipmapsWithCPU(const gl::Context *context); 375 376 angle::Result generateMipmapLevelsWithCPU(ContextVk *contextVk, 377 const angle::Format &sourceFormat, 378 GLuint layer, 379 gl::LevelIndex firstMipLevel, 380 gl::LevelIndex maxMipLevel, 381 const size_t sourceWidth, 382 const size_t sourceHeight, 383 const size_t sourceDepth, 384 const size_t sourceRowPitch, 385 const size_t sourceDepthPitch, 386 uint8_t *sourceData); 387 388 angle::Result copySubImageImpl(const gl::Context *context, 389 const gl::ImageIndex &index, 390 const gl::Offset &destOffset, 391 const gl::Rectangle &sourceArea, 392 const gl::InternalFormat &internalFormat, 393 gl::Framebuffer *source); 394 395 angle::Result copySubTextureImpl(ContextVk *contextVk, 396 const gl::ImageIndex &index, 397 const gl::Offset &dstOffset, 398 const gl::InternalFormat &dstFormat, 399 gl::LevelIndex sourceLevelGL, 400 const gl::Box &sourceBox, 401 bool unpackFlipY, 402 bool unpackPremultiplyAlpha, 403 bool unpackUnmultiplyAlpha, 404 TextureVk *source); 405 406 angle::Result copySubImageImplWithTransfer(ContextVk *contextVk, 407 const gl::ImageIndex &index, 408 const gl::Offset &dstOffset, 409 const vk::Format &dstFormat, 410 gl::LevelIndex sourceLevelGL, 411 size_t sourceLayer, 412 const gl::Box &sourceBox, 413 vk::ImageHelper *srcImage); 414 415 angle::Result copySubImageImplWithDraw(ContextVk *contextVk, 416 const gl::ImageIndex &index, 417 const gl::Offset &dstOffset, 418 const vk::Format &dstFormat, 419 gl::LevelIndex sourceLevelGL, 420 const gl::Box &sourceBox, 421 bool isSrcFlipY, 422 bool unpackFlipY, 423 bool unpackPremultiplyAlpha, 424 bool unpackUnmultiplyAlpha, 425 vk::ImageHelper *srcImage, 426 const vk::ImageView *srcView, 427 SurfaceRotation srcFramebufferRotation); 428 429 angle::Result initImage(ContextVk *contextVk, 430 angle::FormatID intendedImageFormatID, 431 angle::FormatID actualImageFormatID, 432 ImageMipLevels mipLevels); 433 void releaseImage(ContextVk *contextVk); 434 void releaseStagingBuffer(ContextVk *contextVk); 435 uint32_t getMipLevelCount(ImageMipLevels mipLevels) const; 436 uint32_t getMaxLevelCount() const; 437 angle::Result copyAndStageImageData(ContextVk *contextVk, 438 gl::LevelIndex previousFirstAllocateLevel, 439 vk::ImageHelper *srcImage, 440 vk::ImageHelper *dstImage); 441 angle::Result reinitImageAsRenderable(ContextVk *contextVk, 442 const vk::Format &format, 443 gl::TexLevelMask skipLevelsMask); 444 angle::Result initImageViews(ContextVk *contextVk, 445 const angle::Format &format, 446 const bool sized, 447 uint32_t levelCount, 448 uint32_t layerCount); 449 void initSingleLayerRenderTargets(ContextVk *contextVk, 450 GLuint layerCount, 451 gl::LevelIndex levelIndexGL, 452 gl::RenderToTextureImageIndex renderToTextureIndex); 453 RenderTargetVk *getMultiLayerRenderTarget(ContextVk *contextVk, 454 gl::LevelIndex level, 455 GLuint layerIndex, 456 GLuint layerCount); 457 angle::Result getLevelLayerImageView(ContextVk *contextVk, 458 gl::LevelIndex levelGL, 459 size_t layer, 460 const vk::ImageView **imageViewOut); 461 462 // Flush image's staged updates for all levels and layers. 463 angle::Result flushImageStagedUpdates(ContextVk *contextVk); 464 465 const gl::InternalFormat &getImplementationSizedFormat(const gl::Context *context) const; 466 const vk::Format &getBaseLevelFormat(RendererVk *renderer) const; 467 // Queues a flush of any modified image attributes. The image will be reallocated with its new 468 // attributes at the next opportunity. 469 angle::Result respecifyImageStorage(ContextVk *contextVk); 470 471 // Update base and max levels, and re-create image if needed. 472 angle::Result maybeUpdateBaseMaxLevels(ContextVk *contextVk, bool *didRespecifyOut); 473 474 bool isFastUnpackPossible(const vk::Format &vkFormat, size_t offset) const; 475 476 bool shouldUpdateBeStaged(gl::LevelIndex textureLevelIndexGL, 477 angle::FormatID dstFormatID) const; 478 479 // We monitor the staging buffer and set dirty bits if the staging buffer changes. Note that we 480 // support changes in the staging buffer even outside the TextureVk class. 481 void onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message) override; 482 getTilingMode()483 ANGLE_INLINE VkImageTiling getTilingMode() 484 { 485 return (mImage->valid()) ? mImage->getTilingMode() : VK_IMAGE_TILING_OPTIMAL; 486 } 487 488 angle::Result refreshImageViews(ContextVk *contextVk); 489 bool shouldDecodeSRGB(ContextVk *contextVk, GLenum srgbDecode, bool texelFetchStaticUse) const; 490 void initImageUsageFlags(ContextVk *contextVk, angle::FormatID actualFormatID); 491 void handleImmutableSamplerTransition(const vk::ImageHelper *previousImage, 492 const vk::ImageHelper *nextImage); 493 getRequiredImageAccess()494 vk::ImageAccess getRequiredImageAccess() const { return mRequiredImageAccess; } 495 bool imageHasActualImageFormat(angle::FormatID actualFormatID) const; 496 497 bool mOwnsImage; 498 bool mRequiresMutableStorage; 499 vk::ImageAccess mRequiredImageAccess; 500 bool mImmutableSamplerDirty; 501 502 gl::TextureType mImageNativeType; 503 504 // The layer offset to apply when converting from a frontend texture layer to a texture layer in 505 // mImage. Used when this texture sources a cube map face or 3D texture layer from an EGL image. 506 uint32_t mImageLayerOffset; 507 508 // The level offset to apply when converting from a frontend texture level to texture level in 509 // mImage. 510 uint32_t mImageLevelOffset; 511 512 // If multisampled rendering to texture, an intermediate multisampled image is created for use 513 // as renderpass color attachment. An array of images and image views are used based on the 514 // number of samples used with multisampled rendering to texture. Index 0 corresponds to the 515 // non-multisampled-render-to-texture usage of the texture. 516 517 // - index 0: Unused. See description of |mImage|. 518 // - index N: intermediate multisampled image used for multisampled rendering to texture with 519 // 1 << N samples 520 gl::RenderToTextureImageMap<vk::ImageHelper> mMultisampledImages; 521 522 // |ImageViewHelper| contains all the current views for the Texture. The views are always owned 523 // by the Texture and are not shared like |mImage|. They also have different lifetimes and can 524 // be reallocated independently of |mImage| on state changes. 525 // 526 // - index 0: views for the texture's image (regardless of |mOwnsImage|). 527 // - index N: views for mMultisampledImages[N] 528 gl::RenderToTextureImageMap<vk::ImageViewHelper> mMultisampledImageViews; 529 530 // Texture buffers create texel buffer views instead. |BufferViewHelper| contains the views 531 // corresponding to the attached buffer range. 532 vk::BufferViewHelper mBufferViews; 533 534 // Render targets stored as array of vector of vectors 535 // 536 // - First dimension: index N contains render targets with views from mMultisampledImageViews[N] 537 // - Second dimension: level 538 // - Third dimension: layer 539 gl::RenderToTextureImageMap<std::vector<RenderTargetVector>> mSingleLayerRenderTargets; 540 // Multi-layer render targets stored as a hash map. This is used for layered attachments 541 // which covers the entire layer (glFramebufferTextureLayer) or multiview attachments which 542 // cover a range of layers (glFramebufferTextureMultiviewOVR). 543 angle::HashMap<vk::ImageSubresourceRange, std::unique_ptr<RenderTargetVk>> 544 mMultiLayerRenderTargets; 545 546 // |mImage| wraps a VkImage and VkDeviceMemory that represents the gl::Texture. |mOwnsImage| 547 // indicates that |TextureVk| owns the image. Otherwise it is a weak pointer shared with another 548 // class. Due to this sharing, for example through EGL images, the image must always be 549 // dynamically allocated as the texture can release ownership for example and it can be 550 // transferred to another |TextureVk|. 551 vk::ImageHelper *mImage; 552 553 // |mSampler| contains the relevant Vulkan sampler states representing the OpenGL Texture 554 // sampling states for the Texture. 555 vk::SamplerBinding mSampler; 556 557 // Overridden in some tests. 558 size_t mStagingBufferInitialSize; 559 560 // The created vkImage usage flag. 561 VkImageUsageFlags mImageUsageFlags; 562 563 // Additional image create flags 564 VkImageCreateFlags mImageCreateFlags; 565 566 // If an image level is incompatibly redefined, the image lives through the call that did this 567 // (i.e. set and copy levels), because the image may be used by the framebuffer in the very same 568 // call. As a result, updates to this redefined level are staged (in both the call that 569 // redefines it, and any future calls such as subimage updates). This bitset flags redefined 570 // levels so that their updates will be force-staged until image is recreated. 571 // 572 // In common cases with mipmapped textures, the base/max level would need adjusting as the 573 // texture is no longer mip-complete. However, if every level is redefined such that at the end 574 // the image becomes mip-complete again, no reinitialization of the image is done. This bitset 575 // is additionally used to ensure the image is recreated in the next syncState, if not already. 576 // 577 // Note: this bitmask is for gl::LevelIndex, not vk::LevelIndex 578 gl::TexLevelMask mRedefinedLevels; 579 580 angle::ObserverBinding mImageObserverBinding; 581 582 // Saved between updates. 583 gl::LevelIndex mCurrentBaseLevel; 584 gl::LevelIndex mCurrentMaxLevel; 585 }; 586 587 } // namespace rx 588 589 #endif // LIBANGLE_RENDERER_VULKAN_TEXTUREVK_H_ 590