• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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