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/Common/GPU/Vulkan/VulkanQueueRunner.h
Views: 1401
1
#pragma once
2
3
#include <cstdint>
4
#include <mutex>
5
#include <condition_variable>
6
7
#include "Common/Thread/Promise.h"
8
#include "Common/Data/Collections/Hashmaps.h"
9
#include "Common/Data/Collections/FastVec.h"
10
#include "Common/GPU/Vulkan/VulkanContext.h"
11
#include "Common/GPU/Vulkan/VulkanBarrier.h"
12
#include "Common/GPU/Vulkan/VulkanFrameData.h"
13
#include "Common/GPU/Vulkan/VulkanFramebuffer.h"
14
#include "Common/Data/Convert/SmallDataConvert.h"
15
#include "Common/Data/Collections/TinySet.h"
16
#include "Common/GPU/DataFormat.h"
17
18
class VKRFramebuffer;
19
struct VKRGraphicsPipeline;
20
struct VKRComputePipeline;
21
struct VKRImage;
22
struct VKRPipelineLayout;
23
struct FrameData;
24
25
enum {
26
QUEUE_HACK_MGS2_ACID = 1,
27
QUEUE_HACK_SONIC = 2,
28
QUEUE_HACK_RENDERPASS_MERGE = 8,
29
};
30
31
enum class VKRRenderCommand : uint8_t {
32
REMOVED,
33
BIND_GRAPHICS_PIPELINE, // async
34
STENCIL,
35
BLEND,
36
VIEWPORT,
37
SCISSOR,
38
CLEAR,
39
DRAW,
40
DRAW_INDEXED,
41
PUSH_CONSTANTS,
42
DEBUG_ANNOTATION,
43
NUM_RENDER_COMMANDS,
44
};
45
46
enum class PipelineFlags : u8 {
47
NONE = 0,
48
USES_BLEND_CONSTANT = (1 << 1),
49
USES_DEPTH_STENCIL = (1 << 2), // Reads or writes the depth or stencil buffers.
50
USES_GEOMETRY_SHADER = (1 << 3),
51
USES_MULTIVIEW = (1 << 4), // Inherited from the render pass it was created with.
52
USES_DISCARD = (1 << 5),
53
USES_FLAT_SHADING = (1 << 6),
54
};
55
ENUM_CLASS_BITOPS(PipelineFlags);
56
57
struct VkRenderData {
58
VKRRenderCommand cmd;
59
union {
60
struct {
61
VKRGraphicsPipeline *pipeline;
62
VKRPipelineLayout *pipelineLayout;
63
} graphics_pipeline;
64
struct {
65
uint32_t descSetIndex;
66
int numUboOffsets;
67
uint32_t uboOffsets[3];
68
VkBuffer vbuffer;
69
VkDeviceSize voffset;
70
uint32_t count;
71
uint32_t offset;
72
} draw;
73
struct {
74
uint32_t descSetIndex;
75
uint32_t uboOffsets[3];
76
uint16_t numUboOffsets;
77
uint16_t instances;
78
VkBuffer vbuffer;
79
VkBuffer ibuffer;
80
uint32_t voffset;
81
uint32_t ioffset;
82
uint32_t count;
83
} drawIndexed;
84
struct {
85
uint32_t clearColor;
86
float clearZ;
87
int clearStencil;
88
int clearMask; // VK_IMAGE_ASPECT_COLOR_BIT etc
89
} clear;
90
struct {
91
VkViewport vp;
92
} viewport;
93
struct {
94
VkRect2D scissor;
95
} scissor;
96
struct {
97
uint8_t stencilWriteMask;
98
uint8_t stencilCompareMask;
99
uint8_t stencilRef;
100
} stencil;
101
struct {
102
uint32_t color;
103
} blendColor;
104
struct {
105
VkShaderStageFlags stages;
106
uint8_t offset;
107
uint8_t size;
108
uint8_t data[40]; // Should be enough for now.
109
} push;
110
struct {
111
const char *annotation;
112
} debugAnnotation;
113
struct {
114
int setIndex;
115
} bindDescSet;
116
};
117
};
118
119
enum class VKRStepType : uint8_t {
120
RENDER,
121
RENDER_SKIP,
122
COPY,
123
BLIT,
124
READBACK,
125
READBACK_IMAGE,
126
};
127
128
struct TransitionRequest {
129
VKRFramebuffer *fb;
130
VkImageAspectFlags aspect; // COLOR or DEPTH
131
VkImageLayout targetLayout;
132
133
bool operator == (const TransitionRequest &other) const {
134
return fb == other.fb && aspect == other.aspect && targetLayout == other.targetLayout;
135
}
136
};
137
138
class VKRRenderPass;
139
140
struct VKRStep {
141
VKRStep(VKRStepType _type) : stepType(_type) {}
142
~VKRStep() {}
143
144
VKRStepType stepType;
145
FastVec<VkRenderData> commands;
146
TinySet<TransitionRequest, 4> preTransitions;
147
TinySet<VKRFramebuffer *, 8> dependencies;
148
const char *tag;
149
union {
150
struct {
151
VKRFramebuffer *framebuffer;
152
VKRRenderPassLoadAction colorLoad;
153
VKRRenderPassLoadAction depthLoad;
154
VKRRenderPassLoadAction stencilLoad;
155
VKRRenderPassStoreAction colorStore;
156
VKRRenderPassStoreAction depthStore;
157
VKRRenderPassStoreAction stencilStore;
158
uint32_t clearColor;
159
float clearDepth;
160
u8 clearStencil;
161
int numDraws;
162
// Downloads and textures from this pass.
163
int numReads;
164
VkImageLayout finalColorLayout;
165
VkImageLayout finalDepthStencilLayout;
166
PipelineFlags pipelineFlags; // contains the self dependency flag, in the form of USES_INPUT_ATTACHMENT
167
VkRect2D renderArea;
168
// Render pass type. Deduced after finishing recording the pass, from the used pipelines.
169
// NOTE: Storing the render pass here doesn't do much good, we change the compatible parameters (load/store ops) during step optimization.
170
RenderPassType renderPassType;
171
} render;
172
struct {
173
VKRFramebuffer *src;
174
VKRFramebuffer *dst;
175
VkRect2D srcRect;
176
VkOffset2D dstPos;
177
VkImageAspectFlags aspectMask;
178
} copy;
179
struct {
180
VKRFramebuffer *src;
181
VKRFramebuffer *dst;
182
VkRect2D srcRect;
183
VkRect2D dstRect;
184
VkImageAspectFlags aspectMask;
185
VkFilter filter;
186
} blit;
187
struct {
188
VKRFramebuffer *src;
189
VkRect2D srcRect;
190
VkImageAspectFlags aspectMask;
191
bool delayed;
192
} readback;
193
struct {
194
VkImage image;
195
VkRect2D srcRect;
196
int mipLevel;
197
} readback_image;
198
};
199
};
200
201
// These are enqueued from the main thread,
202
// and the render thread pops them off
203
struct VKRRenderThreadTask {
204
VKRRenderThreadTask(VKRRunType _runType) : runType(_runType) {}
205
std::vector<VKRStep *> steps;
206
int frame = -1;
207
VKRRunType runType;
208
209
// Avoid copying these by accident.
210
VKRRenderThreadTask(VKRRenderThreadTask &) = delete;
211
VKRRenderThreadTask &operator =(VKRRenderThreadTask &) = delete;
212
};
213
214
class VulkanQueueRunner {
215
public:
216
VulkanQueueRunner(VulkanContext *vulkan) : vulkan_(vulkan), renderPasses_(16) {}
217
218
void SetBackbuffer(VkFramebuffer fb, VkImage img) {
219
backbuffer_ = fb;
220
backbufferImage_ = img;
221
}
222
223
void PreprocessSteps(std::vector<VKRStep *> &steps);
224
void RunSteps(std::vector<VKRStep *> &steps, int curFrame, FrameData &frameData, FrameDataShared &frameDataShared, bool keepSteps = false);
225
void LogSteps(const std::vector<VKRStep *> &steps, bool verbose);
226
227
static std::string StepToString(VulkanContext *vulkan, const VKRStep &step);
228
229
void CreateDeviceObjects();
230
void DestroyDeviceObjects();
231
232
// Swapchain
233
void DestroyBackBuffers();
234
bool CreateSwapchain(VkCommandBuffer cmdInit, VulkanBarrierBatch *barriers);
235
236
bool HasBackbuffers() const {
237
return !framebuffers_.empty();
238
}
239
240
// Get a render pass that's compatible with all our framebuffers.
241
// Note that it's precached, cannot look up in the map as this might be on another thread.
242
VKRRenderPass *GetCompatibleRenderPass() const {
243
return compatibleRenderPass_;
244
}
245
246
inline int RPIndex(VKRRenderPassLoadAction color, VKRRenderPassLoadAction depth) {
247
return (int)depth * 3 + (int)color;
248
}
249
250
// src == 0 means to copy from the sync readback buffer.
251
bool CopyReadbackBuffer(FrameData &frameData, VKRFramebuffer *src, int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels);
252
253
VKRRenderPass *GetRenderPass(const RPKey &key);
254
255
bool GetRenderPassKey(VKRRenderPass *passToFind, RPKey *outKey) const {
256
bool found = false;
257
renderPasses_.Iterate([passToFind, &found, outKey](const RPKey &rpkey, const VKRRenderPass *pass) {
258
if (pass == passToFind) {
259
found = true;
260
*outKey = rpkey;
261
}
262
});
263
return found;
264
}
265
266
void EnableHacks(uint32_t hacks) {
267
hacksEnabled_ = hacks;
268
}
269
270
private:
271
bool InitBackbufferFramebuffers(int width, int height);
272
bool InitDepthStencilBuffer(VkCommandBuffer cmd, VulkanBarrierBatch *barriers); // Used for non-buffered rendering.
273
274
VKRRenderPass *PerformBindFramebufferAsRenderTarget(const VKRStep &pass, VkCommandBuffer cmd);
275
void PerformRenderPass(const VKRStep &pass, VkCommandBuffer cmd, int curFrame, QueueProfileContext &profile);
276
void PerformCopy(const VKRStep &pass, VkCommandBuffer cmd);
277
void PerformBlit(const VKRStep &pass, VkCommandBuffer cmd);
278
void PerformReadback(const VKRStep &pass, VkCommandBuffer cmd, FrameData &frameData);
279
void PerformReadbackImage(const VKRStep &pass, VkCommandBuffer cmd);
280
281
void LogRenderPass(const VKRStep &pass, bool verbose);
282
void LogCopy(const VKRStep &pass);
283
void LogBlit(const VKRStep &pass);
284
void LogReadback(const VKRStep &pass);
285
void LogReadbackImage(const VKRStep &pass);
286
287
void ResizeReadbackBuffer(CachedReadback *readback, VkDeviceSize requiredSize);
288
289
static void ApplyMGSHack(std::vector<VKRStep *> &steps);
290
static void ApplySonicHack(std::vector<VKRStep *> &steps);
291
static void ApplyRenderPassMerge(std::vector<VKRStep *> &steps);
292
293
static void SetupTransferDstWriteAfterWrite(VKRImage &img, VkImageAspectFlags aspect, VulkanBarrierBatch *recordBarrier);
294
295
VulkanContext *vulkan_;
296
297
VkFramebuffer backbuffer_ = VK_NULL_HANDLE;
298
VkImage backbufferImage_ = VK_NULL_HANDLE;
299
300
// The "Compatible" render pass. Should be able to get rid of this soon.
301
VKRRenderPass *compatibleRenderPass_ = nullptr;
302
303
// Renderpasses, all combinations of preserving or clearing or dont-care-ing fb contents.
304
// Each VKRRenderPass contains all compatibility classes (which attachments they have, etc).
305
DenseHashMap<RPKey, VKRRenderPass *> renderPasses_;
306
307
// Readback buffer. Currently we only support synchronous readback, so we only really need one.
308
// We size it generously.
309
CachedReadback syncReadback_{};
310
311
// TODO: Enable based on compat.ini.
312
uint32_t hacksEnabled_ = 0;
313
314
// Image barrier helper used during command buffer record (PerformRenderPass etc).
315
// Stored here to help reuse the allocation.
316
317
VulkanBarrierBatch recordBarrier_;
318
319
// Swap chain management
320
struct SwapchainImageData {
321
VkImage image;
322
VkImageView view;
323
};
324
std::vector<VkFramebuffer> framebuffers_;
325
std::vector<SwapchainImageData> swapchainImages_;
326
uint32_t swapchainImageCount_ = 0;
327
struct DepthBufferInfo {
328
VkFormat format = VK_FORMAT_UNDEFINED;
329
VkImage image = VK_NULL_HANDLE;
330
VmaAllocation alloc = VK_NULL_HANDLE;
331
VkImageView view = VK_NULL_HANDLE;
332
};
333
DepthBufferInfo depth_;
334
};
335
336
const char *VKRRenderCommandToString(VKRRenderCommand cmd);
337
338