1 // Copyright 2023 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 <unordered_map>
20 
21 #include "goldfish_vk_dispatch.h"
22 #include "vulkan/vulkan.h"
23 
24 namespace gfxstream {
25 namespace vk {
26 
27 struct ShaderData {
28     const uint32_t* code;  // Pointer to shader's compiled spir-v code
29     const size_t size;     // size of the code in bytes
30 };
31 
32 struct Etc2PushConstant {
33     uint32_t compFormat;
34     uint32_t baseLayer;
35 };
36 
37 struct AstcPushConstant {
38     uint32_t blockSize[2];
39     uint32_t baseLayer;
40     uint32_t smallBlock;
41 };
42 
43 // Holds the Vulkan resources for the GPU decompression pipeline of a given emulated texture format.
44 // GpuDecompressionPipeline should be reused, use GpuDecompressionPipelineManager for that.
45 class GpuDecompressionPipeline {
46    public:
47     // Factory method. Returns null if pipeline initialization failed.
48     static std::unique_ptr<GpuDecompressionPipeline> create(
49         VulkanDispatch* vk, VkDevice device, VkFormat compressedFormat,
50         VkImageType imageType, VkDescriptorSetLayout descriptorSetLayout,
51         VkPipelineLayout pipelineLayout);
52 
53     // GpuDecompressionPipeline is neither copyable nor movable.
54     // This allows us to safely release Vulkan resources in the destructor
55     GpuDecompressionPipeline(const GpuDecompressionPipeline&) = delete;
56     GpuDecompressionPipeline& operator=(const GpuDecompressionPipeline&) = delete;
57 
58     // Destructor, will release any Vulkan resource we hold
59     ~GpuDecompressionPipeline();
60 
61     // Accessors
pipeline()62     VkPipeline pipeline() const { return mPipeline; }
pipelineLayout()63     VkPipelineLayout pipelineLayout() const { return mPipelineLayout; }
descriptorSetLayout()64     VkDescriptorSetLayout descriptorSetLayout() const { return mDescriptorSetLayout; }
65 
66    private:
67     GpuDecompressionPipeline(VulkanDispatch* vk, VkDevice device,
68                              VkFormat compressedFormat, VkImageType imageType,
69                              VkDescriptorSetLayout descriptorSetLayout,
70                              VkPipelineLayout pipelineLayout);
71 
72     // Initializes the compute shader pipeline
73     bool initialize();
74 
75     // Member variables set in the constructor
76     VulkanDispatch* mVk;
77     VkDevice mDevice;
78     VkFormat mCompressedFormat;
79     VkImageType mImageType;
80     VkDescriptorSetLayout mDescriptorSetLayout;
81     VkPipelineLayout mPipelineLayout;
82 
83     // Member variables set by initialize()
84     VkPipeline mPipeline = VK_NULL_HANDLE;
85 };
86 
87 enum class AstcDecoder{Old, NewRgb, NewBc3};
88 
89 // Acts as a cache for GpuDecompressionPipeline objects
90 // Currently no eviction strategy, but the maximum number of entries is bounded by the number of
91 // compressed formats that we emulate.
92 // Thread-safety: not thread safe. Access to members of this class must be synchronized externally.
93 class GpuDecompressionPipelineManager {
94    public:
95     // TODO(gregschlom) remove this once we fully remove the old decoder
96     static void setAstcDecoder(AstcDecoder value);
97     static AstcDecoder astcDecoder();
98 
99     GpuDecompressionPipelineManager(VulkanDispatch* vk, VkDevice device);
100 
101     // Returns the cached pipeline for the decompression of a given image format and type.
102     // If the pipeline doesn't exist yet, it will be created and initialized.
103     // Returns null if initialization of the pipeline failed.
104     GpuDecompressionPipeline* get(VkFormat compressedFormat, VkImageType imageType);
105 
106     // Erases everything from the cache
107     void clear();
108 
109     ~GpuDecompressionPipelineManager();
110 
111     // GpuDecompressionPipelineManager is neither copyable nor movable.
112     // This allows us to safely release Vulkan resources in the destructor
113     GpuDecompressionPipelineManager(const GpuDecompressionPipelineManager&) = delete;
114     GpuDecompressionPipelineManager& operator=(const GpuDecompressionPipelineManager&) = delete;
115 
116    private:
117     VkDescriptorSetLayout getDescriptorSetLayout();
118     VkPipelineLayout getPipelineLayout(VkFormat format);
119 
120     std::unordered_map<const ShaderData*, std::unique_ptr<GpuDecompressionPipeline>> mPipelines;
121 
122     VulkanDispatch* mVk = nullptr;
123     VkDevice mDevice = VK_NULL_HANDLE;
124     VkDescriptorSetLayout mDescriptorSetLayout = VK_NULL_HANDLE;
125     VkPipelineLayout mAstcPipelineLayout = VK_NULL_HANDLE;
126     VkPipelineLayout mEtc2PipelineLayout = VK_NULL_HANDLE;
127 };
128 
129 }  // namespace vk
130 }  // namespace gfxstream
131