Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/GPU/Vulkan/VulkanUtil.cpp
5654 views
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
#include <string>
19
#include "Common/Log.h"
20
#include "Common/StringUtils.h"
21
#include "Common/GPU/Vulkan/VulkanContext.h"
22
#include "Common/Data/Text/Parsers.h"
23
#include "Core/Config.h"
24
#include "Core/FrameTiming.h"
25
#include "GPU/Vulkan/VulkanUtil.h"
26
27
#ifdef _DEBUG
28
static const bool g_Validate = true;
29
#else
30
static const bool g_Validate = false;
31
#endif
32
33
using namespace PPSSPP_VK;
34
35
const VkComponentMapping VULKAN_4444_SWIZZLE = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B };
36
const VkComponentMapping VULKAN_1555_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_A };
37
const VkComponentMapping VULKAN_565_SWIZZLE = { VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_IDENTITY };
38
const VkComponentMapping VULKAN_8888_SWIZZLE = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY };
39
40
VkPresentModeKHR ConfigPresentModeToVulkan(Draw::DrawContext *draw) {
41
g_frameTiming.ComputePresentMode(draw, false);
42
Draw::PresentMode presentMode = g_frameTiming.PresentMode();
43
switch (presentMode) {
44
case Draw::PresentMode::IMMEDIATE:
45
return VK_PRESENT_MODE_IMMEDIATE_KHR;
46
case Draw::PresentMode::MAILBOX:
47
return VK_PRESENT_MODE_MAILBOX_KHR;
48
case Draw::PresentMode::FIFO:
49
default:
50
return VK_PRESENT_MODE_FIFO_KHR;
51
}
52
}
53
54
// TODO: Share this between backends.
55
static VulkanInitFlags VulkanInitFlagsFromConfig() {
56
VulkanInitFlags flags = (VulkanInitFlags)0;
57
if (g_Validate) {
58
flags |= VulkanInitFlags::VALIDATE;
59
}
60
if (g_Config.bVulkanDisableImplicitLayers) {
61
flags |= VulkanInitFlags::DISABLE_IMPLICIT_LAYERS;
62
}
63
return flags;
64
}
65
66
void InitVulkanCreateInfoFromConfig(VulkanContext::CreateInfo *info) {
67
Version gitVer(PPSSPP_GIT_VERSION);
68
info->app_name = "PPSSPP";
69
info->app_ver = gitVer.ToInteger();
70
info->flags = VulkanInitFlagsFromConfig();
71
info->customDriver = g_Config.sCustomDriver;
72
}
73
74
VkShaderModule CompileShaderModule(VulkanContext *vulkan, VkShaderStageFlagBits stage, const char *code, std::string *error) {
75
std::vector<uint32_t> spirv;
76
bool success = GLSLtoSPV(stage, code, GLSLVariant::VULKAN, spirv, error);
77
if (!error->empty()) {
78
if (success) {
79
ERROR_LOG(Log::G3D, "Warnings in shader compilation!");
80
} else {
81
ERROR_LOG(Log::G3D, "Error in shader compilation!");
82
}
83
ERROR_LOG(Log::G3D, "Messages: %s", error->c_str());
84
ERROR_LOG(Log::G3D, "Shader source:\n%s", LineNumberString(code).c_str());
85
OutputDebugStringUTF8("Messages:\n");
86
OutputDebugStringUTF8(error->c_str());
87
OutputDebugStringUTF8(LineNumberString(code).c_str());
88
return VK_NULL_HANDLE;
89
} else {
90
VkShaderModule module;
91
if (vulkan->CreateShaderModule(spirv, &module, stage == VK_SHADER_STAGE_VERTEX_BIT ? "system_vs" : "system_fs")) {
92
return module;
93
} else {
94
return VK_NULL_HANDLE;
95
}
96
}
97
}
98
99
VulkanComputeShaderManager::VulkanComputeShaderManager(VulkanContext *vulkan) : vulkan_(vulkan), pipelines_(8) {}
100
VulkanComputeShaderManager::~VulkanComputeShaderManager() {}
101
102
void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) {
103
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
104
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
105
_assert_(VK_SUCCESS == res);
106
107
static const BindingType bindingTypes[3] = {
108
BindingType::STORAGE_IMAGE_COMPUTE,
109
BindingType::STORAGE_BUFFER_COMPUTE,
110
BindingType::STORAGE_BUFFER_COMPUTE,
111
};
112
113
VkDescriptorSetLayoutBinding bindings[3] = {};
114
bindings[0].descriptorCount = 1;
115
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
116
bindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
117
bindings[0].binding = 0;
118
bindings[1].descriptorCount = 1;
119
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
120
bindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
121
bindings[1].binding = 1;
122
bindings[2].descriptorCount = 1;
123
bindings[2].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
124
bindings[2].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
125
bindings[2].binding = 2;
126
127
VkDevice device = vulkan_->GetDevice();
128
129
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
130
dsl.bindingCount = ARRAY_SIZE(bindings);
131
dsl.pBindings = bindings;
132
res = vkCreateDescriptorSetLayout(device, &dsl, nullptr, &descriptorSetLayout_);
133
_assert_(VK_SUCCESS == res);
134
135
for (int i = 0; i < ARRAY_SIZE(frameData_); i++) {
136
frameData_[i].descPool.Create(vulkan_, bindingTypes, ARRAY_SIZE(bindingTypes), 4096);
137
frameData_[i].descPoolUsed = false;
138
}
139
140
VkPushConstantRange push = {};
141
push.offset = 0;
142
push.size = 16;
143
push.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;
144
145
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
146
pl.pPushConstantRanges = &push;
147
pl.pushConstantRangeCount = 1;
148
VkDescriptorSetLayout setLayouts[1] = { descriptorSetLayout_ };
149
pl.setLayoutCount = ARRAY_SIZE(setLayouts);
150
pl.pSetLayouts = setLayouts;
151
pl.flags = 0;
152
res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_);
153
_assert_(VK_SUCCESS == res);
154
}
155
156
void VulkanComputeShaderManager::DestroyDeviceObjects() {
157
for (int i = 0; i < ARRAY_SIZE(frameData_); i++) {
158
frameData_[i].descPool.Destroy();
159
}
160
if (descriptorSetLayout_) {
161
vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_);
162
}
163
pipelines_.Iterate([&](const PipelineKey &key, VkPipeline pipeline) {
164
vulkan_->Delete().QueueDeletePipeline(pipeline);
165
});
166
pipelines_.Clear();
167
168
if (pipelineLayout_) {
169
vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_);
170
}
171
if (pipelineCache_ != VK_NULL_HANDLE) {
172
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_);
173
}
174
}
175
176
VkDescriptorSet VulkanComputeShaderManager::GetDescriptorSet(VkImageView image, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkBuffer buffer2, VkDeviceSize offset2, VkDeviceSize range2) {
177
int curFrame = vulkan_->GetCurFrame();
178
FrameData &frameData = frameData_[curFrame];
179
frameData.descPoolUsed = true;
180
VkDescriptorSet desc;
181
frameData.descPool.Allocate(&desc, 1, &descriptorSetLayout_);
182
_assert_(desc != VK_NULL_HANDLE);
183
184
VkWriteDescriptorSet writes[3]{};
185
int n = 0;
186
VkDescriptorImageInfo imageInfo = {};
187
VkDescriptorBufferInfo bufferInfo[2] = {};
188
if (image) {
189
imageInfo.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
190
imageInfo.imageView = image;
191
imageInfo.sampler = VK_NULL_HANDLE;
192
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
193
writes[n].dstBinding = 0;
194
writes[n].pImageInfo = &imageInfo;
195
writes[n].descriptorCount = 1;
196
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
197
writes[n].dstSet = desc;
198
n++;
199
}
200
bufferInfo[0].buffer = buffer;
201
bufferInfo[0].offset = offset;
202
bufferInfo[0].range = range;
203
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
204
writes[n].dstBinding = 1;
205
writes[n].pBufferInfo = &bufferInfo[0];
206
writes[n].descriptorCount = 1;
207
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
208
writes[n].dstSet = desc;
209
n++;
210
if (buffer2) {
211
bufferInfo[1].buffer = buffer2;
212
bufferInfo[1].offset = offset2;
213
bufferInfo[1].range = range2;
214
writes[n].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
215
writes[n].dstBinding = 2;
216
writes[n].pBufferInfo = &bufferInfo[1];
217
writes[n].descriptorCount = 1;
218
writes[n].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
219
writes[n].dstSet = desc;
220
n++;
221
}
222
vkUpdateDescriptorSets(vulkan_->GetDevice(), n, writes, 0, nullptr);
223
return desc;
224
}
225
226
VkPipeline VulkanComputeShaderManager::GetPipeline(VkShaderModule cs) {
227
PipelineKey key{ cs };
228
VkPipeline pipeline;
229
if (pipelines_.Get(key, &pipeline)) {
230
return pipeline;
231
}
232
233
VkComputePipelineCreateInfo pci{ VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO };
234
pci.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
235
pci.stage.module = cs;
236
pci.stage.pName = "main";
237
pci.stage.stage = VK_SHADER_STAGE_COMPUTE_BIT;
238
pci.layout = pipelineLayout_;
239
pci.flags = 0;
240
241
VkResult res = vkCreateComputePipelines(vulkan_->GetDevice(), pipelineCache_, 1, &pci, nullptr, &pipeline);
242
_assert_(res == VK_SUCCESS);
243
244
pipelines_.Insert(key, pipeline);
245
return pipeline;
246
}
247
248
void VulkanComputeShaderManager::BeginFrame() {
249
int curFrame = vulkan_->GetCurFrame();
250
FrameData &frame = frameData_[curFrame];
251
if (frame.descPoolUsed) {
252
frame.descPool.Reset();
253
frame.descPoolUsed = false;
254
}
255
}
256
257