CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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