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 "vulkan/emulated_textures/AstcTexture.h" 23 #include "vulkan/emulated_textures/GpuDecompressionPipeline.h" 24 #include "goldfish_vk_dispatch.h" 25 #include "vulkan/vulkan.h" 26 27 namespace gfxstream { 28 namespace vk { 29 30 class CompressedImageInfo { 31 public: 32 // Static methods 33 34 // Returns the format that this image will be converted to, if the original format isn't 35 // natively supported by the GPU. 36 static VkFormat getOutputFormat(VkFormat compFmt); 37 38 // Returns the image format used to store the compressed data. Each pixel in the compressed 39 // mipmaps will hold an entire compressed block. 40 static VkFormat getCompressedMipmapsFormat(VkFormat compFmt); 41 42 static bool needEmulatedAlpha(VkFormat format); 43 44 // Returns a VkImageCopy to copy to/from the compressed data 45 static VkImageCopy getCompressedMipmapsImageCopy(const VkImageCopy& origRegion, 46 const CompressedImageInfo& srcImg, 47 const CompressedImageInfo& dstImg, 48 bool needEmulatedSrc, bool needEmulatedDst); 49 static VkImageCopy2 getCompressedMipmapsImageCopy(const VkImageCopy2& origRegion, 50 const CompressedImageInfo& srcImg, 51 const CompressedImageInfo& dstImg, 52 bool needEmulatedSrc, bool needEmulatedDst); 53 54 55 // Constructors 56 57 // TODO(gregschlom) Delete these constructors once we switch to holding a 58 // std::unique_ptr<CompressedImageInfo> 59 CompressedImageInfo() = default; 60 explicit CompressedImageInfo(VkDevice device); 61 62 CompressedImageInfo(VkDevice device, const VkImageCreateInfo& createInfo, 63 GpuDecompressionPipelineManager* pipelineManager); 64 65 // Public methods 66 67 // Returns the VkImageCreateInfo needed to create the output image 68 VkImageCreateInfo getOutputCreateInfo(const VkImageCreateInfo& createInfo) const; 69 70 // Creates the compressed mipmap images, that is the VkImages holding the compressed data 71 void createCompressedMipmapImages(VulkanDispatch* vk, const VkImageCreateInfo& createInfo); 72 73 // Initializes the resources needed to perform CPU decompression of ASTC textures 74 void initAstcCpuDecompression(VulkanDispatch* vk, VkPhysicalDevice physicalDevice); 75 76 // Should be called when the guest calls vkCmdPipelineBarrier. 77 // This function checks if the image barrier transitions the compressed image to a layout where 78 // it will be read from, and if so, it decompresses the image. 79 // 80 // outputBarriers: any barrier that needs to be passed to the vkCmdPipelineBarrier call will be 81 // added to this vector. 82 // Returns whether image decompression happened. 83 // Note: the global lock must be held when calling this method, because we call into 84 // GpuDecompressionPipelineManager. 85 bool decompressIfNeeded(VulkanDispatch* vk, VkCommandBuffer commandBuffer, 86 VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, 87 const VkImageMemoryBarrier& targetBarrier, 88 std::vector<VkImageMemoryBarrier>& outputBarriers); 89 90 void decompressOnCpu(VkCommandBuffer commandBuffer, uint8_t* srcAstcData, size_t astcDataSize, 91 VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount, 92 const VkBufferImageCopy* pRegions, const VkDecoderContext& context); 93 94 void decompressOnCpu(VkCommandBuffer commandBuffer, uint8_t* srcAstcData, size_t astcDataSize, 95 const VkCopyBufferToImageInfo2* pCopyBufferToImageInfo, const VkDecoderContext& context); 96 97 VkMemoryRequirements getMemoryRequirements() const; 98 99 VkResult bindCompressedMipmapsMemory(VulkanDispatch* vk, VkDeviceMemory memory, 100 VkDeviceSize memoryOffset); 101 102 // Given a VkBufferImageCopy object for the original image, returns a new 103 // VkBufferImageCopy that points to the same location in the compressed mipmap images. 104 VkBufferImageCopy getBufferImageCopy(const VkBufferImageCopy& origRegion) const; 105 VkBufferImageCopy2 getBufferImageCopy(const VkBufferImageCopy2& origRegion) const; 106 107 // Releases all the resources used by this class. It may no longer be used after calling this. 108 void destroy(VulkanDispatch* vk); 109 110 // Accessors 111 112 bool isEtc2() const; 113 bool isAstc() const; device()114 VkDevice device() const { return mDevice; } compressedMipmap(uint32_t level)115 VkImage compressedMipmap(uint32_t level) { return mCompressedMipmaps[level]; } outputImage()116 VkImage outputImage() { return mOutputImage; } setOutputImage(VkImage image)117 void setOutputImage(VkImage image) { mOutputImage = image; } canDecompressOnCpu()118 bool canDecompressOnCpu() { return mAstcTexture != nullptr; } successfullyDecompressedOnCpu()119 bool successfullyDecompressedOnCpu() const { 120 return mAstcTexture && mAstcTexture->successfullyDecompressed(); 121 } 122 123 private: 124 // Returns a vector of image barriers for the compressed mipmap images and the decompressed 125 // image. 126 std::vector<VkImageMemoryBarrier> getImageBarriers(const VkImageMemoryBarrier& srcBarrier); 127 128 VkImageSubresourceRange getImageSubresourceRange(const VkImageSubresourceRange& range) const; 129 130 // Initializes the compute shader pipeline to decompress the image. 131 // No-op if this was already called successfully. 132 VkResult initializeDecompressionPipeline(VulkanDispatch* vk, VkDevice device); 133 134 // Runs the decompression shader 135 void decompress(VulkanDispatch* vk, VkCommandBuffer commandBuffer, 136 const VkImageSubresourceRange& range); 137 138 // Returns the size of the image at a given mip level 139 VkExtent3D mipmapExtent(uint32_t level) const; 140 // Returns the size of the compressed mipmaps at a given mip level. This is mipmapExtent divided 141 // by the block size, and rounded up. 142 VkExtent3D compressedMipmapExtent(uint32_t level) const; 143 // Returns an extent into the compressed mipmaps. This divides the components of origExtent by 144 // the block size, and the result is clamped to not exceed the compressed mipmap size. 145 VkExtent3D compressedMipmapPortion(const VkExtent3D& origExtent, uint32_t level) const; 146 147 // Member variables 148 149 // The original compressed format of this image. E.g.: VK_FORMAT_ASTC_4x4_UNORM_BLOCK 150 VkFormat mCompressedFormat = VK_FORMAT_UNDEFINED; 151 // The format that we decompressed the image to. E.g.: VK_FORMAT_R8G8B8A8_UINT 152 VkFormat mOutputFormat = VK_FORMAT_UNDEFINED; 153 // The format that we use to store the compressed data, since the original compressed format 154 // isn't available. This holds one compressed block per pixel. E.g.: VK_FORMAT_R32G32B32A32_UINT 155 VkFormat mCompressedMipmapsFormat = VK_FORMAT_UNDEFINED; 156 157 VkImageType mImageType = VK_IMAGE_TYPE_MAX_ENUM; 158 uint32_t mMipLevels = 1; // Number of mip levels in the image 159 VkExtent3D mExtent = {}; // Size of the image 160 VkExtent2D mBlock = {1, 1}; // Size of the compressed blocks 161 uint32_t mLayerCount = 1; 162 163 VkDevice mDevice = VK_NULL_HANDLE; 164 VkImage mOutputImage = VK_NULL_HANDLE; 165 166 // Compressed data. Each mip level of the original image is stored as a separate VkImage, and 167 // each pixel in those images contains an entire compressed block. 168 std::vector<VkImage> mCompressedMipmaps; 169 170 // The memory offset that we will use for each compressed mipmap. 171 std::vector<VkDeviceSize> mMipmapOffsets; 172 173 VkMemoryRequirements mMemoryRequirements; 174 175 // Used to perform CPU decompression of ASTC textures. Null for non-ASTC images. 176 std::unique_ptr<AstcTexture> mAstcTexture = nullptr; 177 178 // Vulkan resources used by the decompression pipeline 179 GpuDecompressionPipelineManager* mPipelineManager = nullptr; 180 GpuDecompressionPipeline* mDecompPipeline = nullptr; 181 std::vector<VkDescriptorSet> mDecompDescriptorSets; 182 VkDescriptorPool mDecompDescriptorPool = VK_NULL_HANDLE; 183 std::vector<VkImageView> mCompressedMipmapsImageViews; 184 std::vector<VkImageView> mOutputImageViews; 185 bool mDecompPipelineInitialized = false; 186 }; 187 188 } // namespace vk 189 } // namespace gfxstream 190