1 // Copyright 2022 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #include <cstdint> 18 #include <memory> 19 #include <string> 20 #include <vector> 21 22 #include "stream-servers/vulkan/emulated_textures/AstcTexture.h" 23 #include "vulkan/cereal/common/goldfish_vk_dispatch.h" 24 #include "vulkan/vulkan.h" 25 26 namespace gfxstream { 27 namespace vk { 28 29 class CompressedImageInfo { 30 public: 31 // Static methods 32 33 static VkFormat getDecompressedFormat(VkFormat compFmt); 34 35 // Returns the image format used to store the compressed data. Each pixel in the compressed 36 // mipmaps will hold an entire compressed block. 37 static VkFormat getCompressedMipmapsFormat(VkFormat compFmt); 38 39 static bool isEtc2(VkFormat format); 40 static bool isAstc(VkFormat format); 41 static bool needEmulatedAlpha(VkFormat format); 42 43 // Returns a VkImageCopy to copy to/from the compressed data 44 static VkImageCopy getCompressedMipmapsImageCopy(const VkImageCopy& origRegion, 45 const CompressedImageInfo& srcImg, 46 const CompressedImageInfo& dstImg, 47 bool needEmulatedSrc, bool needEmulatedDst); 48 49 // Constructors 50 51 // TODO(gregschlom) Delete these constructors once we switch to holding a 52 // std::unique_ptr<CompressedImageInfo> 53 CompressedImageInfo() = default; 54 explicit CompressedImageInfo(VkDevice device); 55 56 CompressedImageInfo(VkDevice device, const VkImageCreateInfo& createInfo); 57 58 // Public methods 59 60 // Returns the VkImageCreateInfo needed to create the decompressed image 61 VkImageCreateInfo getDecompressedCreateInfo(const VkImageCreateInfo& createInfo) const; 62 63 // Creates the compressed mipmap images, that is the VkImages holding the compressed data 64 void createCompressedMipmapImages(VulkanDispatch* vk, const VkImageCreateInfo& createInfo); 65 66 // Initializes the resources needed to perform CPU decompression of ASTC textures 67 void initAstcCpuDecompression(VulkanDispatch* vk, VkPhysicalDevice physicalDevice); 68 69 // Should be called when the guest calls vkCmdPipelineBarrier. 70 // This function checks if the image barrier transitions the compressed image to a layout where 71 // it will be read from, and if so, it decompresses the image. 72 // 73 // outputBarriers: any barrier that needs to be passed to the vkCmdPipelineBarrier call will be 74 // added to this vector. 75 // Returns whether image decompression happened. 76 bool decompressIfNeeded(VulkanDispatch* vk, VkCommandBuffer commandBuffer, 77 VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, 78 const VkImageMemoryBarrier& targetBarrier, 79 std::vector<VkImageMemoryBarrier>& outputBarriers); 80 81 void decompressOnCpu(VkCommandBuffer commandBuffer, uint8_t* srcAstcData, size_t astcDataSize, 82 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, 83 const VkBufferImageCopy* pRegions, const VkDecoderContext& context); 84 85 VkMemoryRequirements getMemoryRequirements() const; 86 87 VkResult bindCompressedMipmapsMemory(VulkanDispatch* vk, VkDeviceMemory memory, 88 VkDeviceSize memoryOffset); 89 90 // Given a VkBufferImageCopy object for the original image, returns a new 91 // VkBufferImageCopy that points to the same location in the compressed mipmap images. 92 VkBufferImageCopy getBufferImageCopy(const VkBufferImageCopy& origRegion) const; 93 94 // Releases all the resources used by this class. It may no longer be used after calling this. 95 void destroy(VulkanDispatch* vk); 96 97 // Accessors 98 99 bool isEtc2() const; 100 bool isAstc() const; device()101 VkDevice device() const { return mDevice; } compressedMipmap(uint32_t level)102 VkImage compressedMipmap(uint32_t level) { return mCompressedMipmaps[level]; } decompressedImage()103 VkImage decompressedImage() { return mDecompressedImage; } setDecompressedImage(VkImage image)104 void setDecompressedImage(VkImage image) { mDecompressedImage = image; } canDecompressOnCpu()105 bool canDecompressOnCpu() { return mAstcTexture && mAstcTexture->canDecompressOnCpu(); } successfullyDecompressedOnCpu()106 bool successfullyDecompressedOnCpu() const { 107 return mAstcTexture && mAstcTexture->successfullyDecompressed(); 108 } 109 110 private: 111 // Returns the size in bytes needed for the storage of a given image. 112 // Also updates the alignment field of this class. 113 VkDeviceSize getImageSize(VulkanDispatch* vk, VkImage image); 114 115 // Returns a vector of image barriers for the compressed mipmap images and the decompressed 116 // image. 117 std::vector<VkImageMemoryBarrier> getImageBarriers(const VkImageMemoryBarrier& srcBarrier); 118 119 VkImageSubresourceRange getImageSubresourceRange(const VkImageSubresourceRange& range) const; 120 121 // Initializes the compute shader pipeline to decompress the image. 122 // No-op if this was already called successfully. 123 VkResult initializeDecompressionPipeline(VulkanDispatch* vk, VkDevice device); 124 125 // Runs the decompression shader 126 void decompress(VulkanDispatch* vk, VkCommandBuffer commandBuffer, 127 const VkImageSubresourceRange& range); 128 129 // Returns the size of the image at a given mip level 130 VkExtent3D mipmapExtent(uint32_t level) const; 131 // Returns the size of the compressed mipmaps at a given mip level. This is mipmapExtent divided 132 // by the block size, and rounded up. 133 VkExtent3D compressedMipmapExtent(uint32_t level) const; 134 // Returns an extent into the compressed mipmaps. This divides the components of origExtent by 135 // the block size, and the result is clamped to not exceed the compressed mipmap size. 136 VkExtent3D compressedMipmapPortion(const VkExtent3D& origExtent, uint32_t level) const; 137 138 // Member variables 139 140 // The original compressed format of this image. E.g.: VK_FORMAT_ASTC_4x4_UNORM_BLOCK 141 VkFormat mCompressedFormat = VK_FORMAT_UNDEFINED; 142 // The format that we decompressed the image to. E.g.: VK_FORMAT_R8G8B8A8_UINT 143 VkFormat mDecompressedFormat = VK_FORMAT_UNDEFINED; 144 // The format that we use to store the compressed data, since the original compressed format 145 // isn't available. This holds one compressed block per pixel. E.g.: VK_FORMAT_R32G32B32A32_UINT 146 VkFormat mCompressedMipmapsFormat = VK_FORMAT_UNDEFINED; 147 148 VkImageType mImageType = VK_IMAGE_TYPE_MAX_ENUM; 149 uint32_t mMipLevels = 1; // Number of mip levels in the image 150 VkExtent3D mExtent = {}; // Size of the image 151 VkExtent2D mBlock = {1, 1}; // Size of the compressed blocks 152 uint32_t mLayerCount = 1; 153 154 VkDevice mDevice = VK_NULL_HANDLE; 155 VkImage mDecompressedImage = VK_NULL_HANDLE; 156 157 // Compressed data. Each mip level of the original image is stored as a separate VkImage, and 158 // each pixel in those images contains an entire compressed block. 159 std::vector<VkImage> mCompressedMipmaps; 160 161 VkDeviceSize mAlignment = 0; 162 std::vector<VkDeviceSize> mMemoryOffsets; 163 164 // Used to perform CPU decompression of ASTC textures. Null for non-ASTC images. 165 std::unique_ptr<AstcTexture> mAstcTexture = nullptr; 166 167 // Vulkan resources used by the decompression pipeline 168 VkShaderModule mDecompShader = VK_NULL_HANDLE; 169 VkPipeline mDecompPipeline = VK_NULL_HANDLE; 170 VkPipelineLayout mDecompPipelineLayout = VK_NULL_HANDLE; 171 std::vector<VkDescriptorSet> mDecompDescriptorSets; 172 VkDescriptorSetLayout mDecompDescriptorSetLayout = VK_NULL_HANDLE; 173 VkDescriptorPool mDecompDescriptorPool = VK_NULL_HANDLE; 174 std::vector<VkImageView> mCompressedMipmapsImageViews; 175 std::vector<VkImageView> mDecompImageViews; 176 }; 177 178 } // namespace vk 179 } // namespace gfxstream 180