1 // Copyright (c) 2016- PPSSPP Project.
2 
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0 or later versions.
6 
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 // GNU General Public License 2.0 for more details.
11 
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
14 
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17 
18 #pragma once
19 
20 #include <tuple>
21 #include <map>
22 
23 #include "Common/Data/Collections/Hashmaps.h"
24 #include "Common/GPU/Vulkan/VulkanContext.h"
25 #include "Common/GPU/Vulkan/VulkanLoader.h"
26 #include "Common/GPU/Vulkan/VulkanImage.h"
27 
28 extern const VkComponentMapping VULKAN_4444_SWIZZLE;
29 extern const VkComponentMapping VULKAN_1555_SWIZZLE;
30 extern const VkComponentMapping VULKAN_565_SWIZZLE;
31 extern const VkComponentMapping VULKAN_8888_SWIZZLE;
32 
33 // Note: some drivers prefer B4G4R4A4_UNORM_PACK16 over R4G4B4A4_UNORM_PACK16.
34 #define VULKAN_4444_FORMAT VK_FORMAT_B4G4R4A4_UNORM_PACK16
35 #define VULKAN_1555_FORMAT VK_FORMAT_A1R5G5B5_UNORM_PACK16
36 #define VULKAN_565_FORMAT  VK_FORMAT_B5G6R5_UNORM_PACK16   // TODO: Does not actually have mandatory support, though R5G6B5 does! See #14602
37 #define VULKAN_8888_FORMAT VK_FORMAT_R8G8B8A8_UNORM
38 
39 // Vulkan doesn't really have the concept of an FBO that owns the images,
40 // but it does have the concept of a framebuffer as a set of attachments.
41 // VulkanFBO is an approximation of the FBO concept the other backends use
42 // to make things as similar as possible without being suboptimal.
43 //
44 // An FBO can be rendered to and used as a texture multiple times in a frame.
45 // Even at multiple sizes, while keeping the same contents.
46 // With GL or D3D we'd just rely on the driver managing duplicates for us, but in
47 // Vulkan we will want to be able to batch up the whole frame and reorder passes
48 // so that all textures are ready before the main scene, instead of switching back and
49 // forth. This comes at a memory cost but will be worth it.
50 //
51 // When we render to a scene, then render to a texture, then go back to the scene and
52 // use that texture, we will register that as a dependency. Then we will walk the DAG
53 // to find the final order of command buffers, and execute it.
54 //
55 // Each FBO will get its own command buffer for each pass.
56 
57 // Similar to a subset of Thin3D, but separate.
58 // This is used for things like postprocessing shaders, depal, etc.
59 // No UBO data is used, only PushConstants.
60 // No transform matrices, only post-proj coordinates.
61 // Two textures can be sampled.
62 // Some simplified depth/stencil modes available.
63 
64 class Vulkan2D {
65 public:
66 	Vulkan2D(VulkanContext *vulkan);
67 	~Vulkan2D();
68 
GetVulkanContext()69 	VulkanContext *GetVulkanContext() const { return vulkan_; }
70 
71 	void DeviceLost();
72 	void DeviceRestore(VulkanContext *vulkan);
73 	void Shutdown();
74 
75 	enum class VK2DDepthStencilMode {
76 		NONE,
77 		STENCIL_REPLACE_ALWAYS,  // Does not draw to color.
78 	};
79 
80 	// The only supported primitive is the triangle strip, for simplicity.
81 	// ReadVertices can be used for vertex-less rendering where you generate verts in the vshader.
82 	VkPipeline GetPipeline(VkRenderPass rp, VkShaderModule vs, VkShaderModule fs, bool readVertices = true, VK2DDepthStencilMode depthStencilMode = VK2DDepthStencilMode::NONE);
GetPipelineLayout()83 	VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
84 	void BeginFrame();
85 	void EndFrame();
86 
87 	void PurgeVertexShader(VkShaderModule s, bool keepPipeline = false);
88 	void PurgeFragmentShader(VkShaderModule s, bool keepPipeline = false);
89 
90 	VkDescriptorSet GetDescriptorSet(VkImageView tex1, VkSampler sampler1, VkImageView tex2, VkSampler sampler2);
91 
92 	struct Vertex {
93 		float x, y, z;
94 		float u, v;
95 	};
96 
97 private:
98 	void InitDeviceObjects();
99 	void DestroyDeviceObjects();
100 
101 	VulkanContext *vulkan_ = nullptr;
102 	VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE;
103 	VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
104 	VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
105 
106 	// Yes, another one...
107 	struct DescriptorSetKey {
108 		VkImageView imageView[2];
109 		VkSampler sampler[2];
110 
111 		bool operator < (const DescriptorSetKey &other) const {
112 			return std::tie(imageView[0], imageView[1], sampler[0], sampler[1]) <
113 				std::tie(other.imageView[0], other.imageView[1], other.sampler[0], other.sampler[1]);
114 		}
115 	};
116 
117 	struct PipelineKey {
118 		VkShaderModule vs;
119 		VkShaderModule fs;
120 		VkRenderPass rp;
121 		VK2DDepthStencilMode depthStencilMode;
122 		bool readVertices;
123 		bool operator < (const PipelineKey &other) const {
124 			return std::tie(vs, fs, rp, depthStencilMode, readVertices) < std::tie(other.vs, other.fs, other.rp, other.depthStencilMode, other.readVertices);
125 		}
126 	};
127 
128 	struct FrameData {
129 		VkDescriptorPool descPool;
130 		std::map<DescriptorSetKey, VkDescriptorSet> descSets;
131 	};
132 
133 	FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES];
134 
135 	std::map<PipelineKey, VkPipeline> pipelines_;
136 	std::vector<VkPipeline> keptPipelines_;
137 };
138 
139 // Manager for compute shaders that upload things (and those have two bindings: a storage buffer to read from and an image to write to).
140 class VulkanComputeShaderManager {
141 public:
142 	VulkanComputeShaderManager(VulkanContext *vulkan);
143 	~VulkanComputeShaderManager();
144 
DeviceLost()145 	void DeviceLost() {
146 		DestroyDeviceObjects();
147 	}
DeviceRestore(VulkanContext * vulkan)148 	void DeviceRestore(VulkanContext *vulkan) {
149 		vulkan_ = vulkan;
150 		InitDeviceObjects();
151 	}
152 
153 	// Note: This doesn't cache. The descriptor is for immediate use only.
154 	VkDescriptorSet GetDescriptorSet(VkImageView image, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkBuffer buffer2 = VK_NULL_HANDLE, VkDeviceSize offset2 = 0, VkDeviceSize range2 = 0);
155 
156 	// This of course caches though.
157 	VkPipeline GetPipeline(VkShaderModule cs);
GetPipelineLayout()158 	VkPipelineLayout GetPipelineLayout() const { return pipelineLayout_; }
159 
160 	void BeginFrame();
161 	void EndFrame();
162 
163 private:
164 	void InitDeviceObjects();
165 	void DestroyDeviceObjects();
166 
167 	VulkanContext *vulkan_ = nullptr;
168 	VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE;
169 	VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE;
170 	VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
171 
172 	struct FrameData {
173 		VkDescriptorPool descPool;
174 		int numDescriptors;
175 	};
176 	FrameData frameData_[VulkanContext::MAX_INFLIGHT_FRAMES]{};
177 
178 	struct PipelineKey {
179 		VkShaderModule module;
180 	};
181 
182 	DenseHashMap<PipelineKey, VkPipeline, (VkPipeline)VK_NULL_HANDLE> pipelines_;
183 };
184 
185 
186 VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code, std::string *error);
187