Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/GPU/Vulkan/thin3d_vulkan.cpp
5661 views
1
// Copyright (c) 2015- 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 <cstdio>
19
#include <vector>
20
#include <string>
21
#include <map>
22
23
#include "Common/Log.h"
24
#include "Common/StringUtils.h"
25
#include "Common/System/Display.h"
26
#include "Common/Math/lin/matrix4x4.h"
27
#include "Common/Data/Convert/SmallDataConvert.h"
28
#include "Common/GPU/thin3d.h"
29
#include "Common/GPU/Vulkan/VulkanRenderManager.h"
30
#include "Common/GPU/Vulkan/VulkanContext.h"
31
#include "Common/GPU/Vulkan/VulkanImage.h"
32
#include "Common/GPU/Vulkan/VulkanMemory.h"
33
#include "Common/GPU/Vulkan/VulkanLoader.h"
34
#include "Common/Thread/Promise.h"
35
36
// For descriptor set 0 (the only one), we use a simple descriptor set for all thin3d rendering: 1 UBO binding point, 3 combined texture/samples.
37
//
38
// binding 0 - uniform buffer
39
// binding 1 - texture/sampler
40
// binding 2 - texture/sampler
41
// binding 3 - texture/sampler
42
//
43
// Vertex data lives in a separate namespace (location = 0, 1, etc).
44
45
using namespace PPSSPP_VK;
46
47
namespace Draw {
48
49
// This can actually be replaced with a cast as the values are in the right order.
50
static const VkCompareOp compToVK[] = {
51
VK_COMPARE_OP_NEVER,
52
VK_COMPARE_OP_LESS,
53
VK_COMPARE_OP_EQUAL,
54
VK_COMPARE_OP_LESS_OR_EQUAL,
55
VK_COMPARE_OP_GREATER,
56
VK_COMPARE_OP_NOT_EQUAL,
57
VK_COMPARE_OP_GREATER_OR_EQUAL,
58
VK_COMPARE_OP_ALWAYS
59
};
60
61
// So can this.
62
static const VkBlendOp blendEqToVk[] = {
63
VK_BLEND_OP_ADD,
64
VK_BLEND_OP_SUBTRACT,
65
VK_BLEND_OP_REVERSE_SUBTRACT,
66
VK_BLEND_OP_MIN,
67
VK_BLEND_OP_MAX,
68
};
69
70
static const VkBlendFactor blendFactorToVk[] = {
71
VK_BLEND_FACTOR_ZERO,
72
VK_BLEND_FACTOR_ONE,
73
VK_BLEND_FACTOR_SRC_COLOR,
74
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
75
VK_BLEND_FACTOR_DST_COLOR,
76
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
77
VK_BLEND_FACTOR_SRC_ALPHA,
78
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
79
VK_BLEND_FACTOR_DST_ALPHA,
80
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
81
VK_BLEND_FACTOR_CONSTANT_COLOR,
82
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
83
VK_BLEND_FACTOR_CONSTANT_ALPHA,
84
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
85
VK_BLEND_FACTOR_SRC1_COLOR,
86
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
87
VK_BLEND_FACTOR_SRC1_ALPHA,
88
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
89
};
90
91
static const VkLogicOp logicOpToVK[] = {
92
VK_LOGIC_OP_CLEAR,
93
VK_LOGIC_OP_SET,
94
VK_LOGIC_OP_COPY,
95
VK_LOGIC_OP_COPY_INVERTED,
96
VK_LOGIC_OP_NO_OP,
97
VK_LOGIC_OP_INVERT,
98
VK_LOGIC_OP_AND,
99
VK_LOGIC_OP_NAND,
100
VK_LOGIC_OP_OR,
101
VK_LOGIC_OP_NOR,
102
VK_LOGIC_OP_XOR,
103
VK_LOGIC_OP_EQUIVALENT,
104
VK_LOGIC_OP_AND_REVERSE,
105
VK_LOGIC_OP_AND_INVERTED,
106
VK_LOGIC_OP_OR_REVERSE,
107
VK_LOGIC_OP_OR_INVERTED,
108
};
109
110
static const VkPrimitiveTopology primToVK[] = {
111
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
112
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
113
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
114
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
115
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
116
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
117
// Tesselation shader primitive.
118
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
119
// The rest are for geometry shaders only.
120
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
121
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
122
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
123
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
124
};
125
126
127
static const VkStencilOp stencilOpToVK[8] = {
128
VK_STENCIL_OP_KEEP,
129
VK_STENCIL_OP_ZERO,
130
VK_STENCIL_OP_REPLACE,
131
VK_STENCIL_OP_INCREMENT_AND_CLAMP,
132
VK_STENCIL_OP_DECREMENT_AND_CLAMP,
133
VK_STENCIL_OP_INVERT,
134
VK_STENCIL_OP_INCREMENT_AND_WRAP,
135
VK_STENCIL_OP_DECREMENT_AND_WRAP,
136
};
137
138
class VKBlendState : public BlendState {
139
public:
140
VkPipelineColorBlendStateCreateInfo info{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
141
std::vector<VkPipelineColorBlendAttachmentState> attachments;
142
};
143
144
class VKDepthStencilState : public DepthStencilState {
145
public:
146
VkPipelineDepthStencilStateCreateInfo info{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
147
};
148
149
class VKRasterState : public RasterState {
150
public:
151
VKRasterState(const RasterStateDesc &desc) {
152
cullFace = desc.cull;
153
frontFace = desc.frontFace;
154
}
155
Facing frontFace;
156
CullMode cullFace;
157
158
void ToVulkan(VkPipelineRasterizationStateCreateInfo *info) const {
159
memset(info, 0, sizeof(*info));
160
info->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
161
info->frontFace = frontFace == Facing::CCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE;
162
switch (cullFace) {
163
case CullMode::BACK: info->cullMode = VK_CULL_MODE_BACK_BIT; break;
164
case CullMode::FRONT: info->cullMode = VK_CULL_MODE_FRONT_BIT; break;
165
case CullMode::FRONT_AND_BACK: info->cullMode = VK_CULL_MODE_FRONT_AND_BACK; break;
166
case CullMode::NONE: info->cullMode = VK_CULL_MODE_NONE; break;
167
}
168
info->polygonMode = VK_POLYGON_MODE_FILL;
169
info->lineWidth = 1.0f;
170
}
171
};
172
173
VkShaderStageFlagBits StageToVulkan(ShaderStage stage) {
174
switch (stage) {
175
case ShaderStage::Vertex: return VK_SHADER_STAGE_VERTEX_BIT;
176
case ShaderStage::Geometry: return VK_SHADER_STAGE_GEOMETRY_BIT;
177
case ShaderStage::Compute: return VK_SHADER_STAGE_COMPUTE_BIT;
178
case ShaderStage::Fragment: return VK_SHADER_STAGE_FRAGMENT_BIT;
179
}
180
return VK_SHADER_STAGE_FRAGMENT_BIT;
181
}
182
183
// Not registering this as a resource holder, instead the pipeline is registered. It will
184
// invoke Compile again to recreate the shader then link them together.
185
class VKShaderModule : public ShaderModule {
186
public:
187
VKShaderModule(ShaderStage stage, std::string_view tag) : stage_(stage), tag_(tag) {
188
vkstage_ = StageToVulkan(stage);
189
}
190
bool Compile(VulkanContext *vulkan, const uint8_t *data, size_t size);
191
const std::string &GetSource() const { return source_; }
192
~VKShaderModule() {
193
if (module_) {
194
VkShaderModule shaderModule = module_->BlockUntilReady();
195
vulkan_->Delete().QueueDeleteShaderModule(shaderModule);
196
vulkan_->Delete().QueueCallback([](VulkanContext *context, void *m) {
197
auto module = (Promise<VkShaderModule> *)m;
198
delete module;
199
}, module_);
200
}
201
}
202
Promise<VkShaderModule> *Get() const { return module_; }
203
ShaderStage GetStage() const override {
204
return stage_;
205
}
206
207
private:
208
VulkanContext *vulkan_ = nullptr;
209
Promise<VkShaderModule> *module_ = nullptr;
210
VkShaderStageFlagBits vkstage_;
211
bool ok_ = false;
212
ShaderStage stage_;
213
std::string source_; // So we can recompile in case of context loss.
214
std::string tag_;
215
};
216
217
bool VKShaderModule::Compile(VulkanContext *vulkan, const uint8_t *data, size_t size) {
218
// We'll need this to free it later.
219
vulkan_ = vulkan;
220
source_ = (const char *)data;
221
std::vector<uint32_t> spirv;
222
std::string errorMessage;
223
if (!GLSLtoSPV(vkstage_, source_.c_str(), GLSLVariant::VULKAN, spirv, &errorMessage)) {
224
WARN_LOG(Log::G3D, "Shader compile to module failed (%s): %s", tag_.c_str(), errorMessage.c_str());
225
return false;
226
}
227
228
// Just for kicks, sanity check the SPIR-V. The disasm isn't perfect
229
// but gives you some idea of what's going on.
230
#if 0
231
std::string disasm;
232
if (DisassembleSPIRV(spirv, &disasm)) {
233
OutputDebugStringA(disasm.c_str());
234
}
235
#endif
236
237
VkShaderModule shaderModule = VK_NULL_HANDLE;
238
if (vulkan->CreateShaderModule(spirv, &shaderModule, tag_.c_str())) {
239
module_ = Promise<VkShaderModule>::AlreadyDone(shaderModule);
240
ok_ = true;
241
} else {
242
WARN_LOG(Log::G3D, "vkCreateShaderModule failed (%s)", tag_.c_str());
243
ok_ = false;
244
}
245
return ok_;
246
}
247
248
class VKInputLayout : public InputLayout {
249
public:
250
VkVertexInputBindingDescription binding;
251
std::vector<VkVertexInputAttributeDescription> attributes;
252
VkPipelineVertexInputStateCreateInfo visc;
253
};
254
255
class VKPipeline : public Pipeline {
256
public:
257
VKPipeline(VulkanContext *vulkan, size_t size, PipelineFlags _flags, const char *tag) : vulkan_(vulkan), flags(_flags), tag_(tag) {
258
uboSize_ = (int)size;
259
ubo_ = new uint8_t[uboSize_];
260
vkrDesc = new VKRGraphicsPipelineDesc();
261
}
262
~VKPipeline() {
263
if (pipeline) {
264
pipeline->QueueForDeletion(vulkan_);
265
}
266
for (auto dep : deps) {
267
dep->Release();
268
}
269
delete[] ubo_;
270
vkrDesc->Release();
271
}
272
273
void SetDynamicUniformData(const void *data, size_t size) {
274
_dbg_assert_((int)size <= uboSize_);
275
memcpy(ubo_, data, size);
276
}
277
278
// Returns the binding offset, and the VkBuffer to bind.
279
size_t PushUBO(VulkanPushPool *buf, VulkanContext *vulkan, VkBuffer *vkbuf) {
280
return buf->Push(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties().properties.limits.minUniformBufferOffsetAlignment, vkbuf);
281
}
282
283
int GetUBOSize() const {
284
return uboSize_;
285
}
286
287
VKRGraphicsPipeline *pipeline = nullptr;
288
VKRGraphicsPipelineDesc *vkrDesc = nullptr;
289
PipelineFlags flags;
290
291
std::vector<VKShaderModule *> deps;
292
293
int stride = 0;
294
int dynamicUniformSize = 0;
295
296
bool usesStencil = false;
297
298
private:
299
VulkanContext *vulkan_;
300
uint8_t *ubo_;
301
int uboSize_;
302
std::string tag_;
303
};
304
305
class VKTexture;
306
class VKBuffer;
307
class VKSamplerState;
308
309
enum {
310
MAX_BOUND_TEXTURES = MAX_TEXTURE_SLOTS,
311
};
312
313
struct DescriptorSetKey {
314
VkImageView imageViews_[MAX_BOUND_TEXTURES];
315
VKSamplerState *samplers_[MAX_BOUND_TEXTURES];
316
VkBuffer buffer_;
317
318
bool operator < (const DescriptorSetKey &other) const {
319
for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) {
320
if (imageViews_[i] < other.imageViews_[i]) return true; else if (imageViews_[i] > other.imageViews_[i]) return false;
321
if (samplers_[i] < other.samplers_[i]) return true; else if (samplers_[i] > other.samplers_[i]) return false;
322
}
323
if (buffer_ < other.buffer_) return true; else if (buffer_ > other.buffer_) return false;
324
return false;
325
}
326
};
327
328
class VKTexture : public Texture {
329
public:
330
VKTexture(VulkanContext *vulkan, const TextureDesc &desc)
331
: vulkan_(vulkan), mipLevels_(desc.mipLevels) {
332
format_ = desc.format;
333
}
334
bool Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const TextureDesc &desc);
335
void Update(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const uint8_t *const *data, TextureCallback callback, int numLevels);
336
337
~VKTexture() {
338
Destroy();
339
}
340
341
VkImageView GetImageView() {
342
if (vkTex_) {
343
return vkTex_->GetImageView();
344
}
345
return VK_NULL_HANDLE; // This would be bad.
346
}
347
348
VkImageView GetImageArrayView() {
349
if (vkTex_) {
350
return vkTex_->GetImageArrayView();
351
}
352
return VK_NULL_HANDLE; // This would be bad.
353
}
354
355
int NumLevels() const {
356
return mipLevels_;
357
}
358
359
private:
360
void UpdateInternal(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t *const *data, TextureCallback callback, int numLevels);
361
362
void Destroy() {
363
if (vkTex_) {
364
vkTex_->Destroy();
365
delete vkTex_;
366
vkTex_ = nullptr;
367
}
368
}
369
370
VulkanContext *vulkan_;
371
VulkanTexture *vkTex_ = nullptr;
372
373
int mipLevels_ = 0;
374
};
375
376
class VKFramebuffer;
377
378
class VKContext : public DrawContext {
379
public:
380
VKContext(VulkanContext *vulkan, bool useRenderThread);
381
~VKContext();
382
383
BackendState GetCurrentBackendState() const override {
384
return BackendState{
385
(u32)renderManager_.GetNumSteps(),
386
true, // Means that the other value is meaningful.
387
};
388
}
389
390
void DebugAnnotate(const char *annotation) override;
391
void Wait() override {
392
vkDeviceWaitIdle(vulkan_->GetDevice());
393
}
394
395
const DeviceCaps &GetDeviceCaps() const override {
396
return caps_;
397
}
398
std::vector<std::string> GetDeviceList() const override {
399
std::vector<std::string> list;
400
for (int i = 0; i < vulkan_->GetNumPhysicalDevices(); i++) {
401
list.emplace_back(vulkan_->GetPhysicalDeviceProperties(i).properties.deviceName);
402
}
403
return list;
404
}
405
std::vector<std::string> GetPresentModeList(std::string_view currentMarkerString) const override {
406
std::vector<std::string> list;
407
for (auto mode : vulkan_->GetAvailablePresentModes()) {
408
std::string str = VulkanPresentModeToString(mode);
409
if (mode == vulkan_->GetPresentMode()) {
410
str += std::string(" (") + std::string(currentMarkerString) + ")";
411
}
412
list.push_back(str);
413
}
414
return list;
415
}
416
std::vector<std::string> GetSurfaceFormatList() const override {
417
std::vector<std::string> list;
418
for (auto &format : vulkan_->SurfaceFormats()) {
419
std::string str = StringFromFormat("%s : %s", VulkanFormatToString(format.format), VulkanColorSpaceToString(format.colorSpace));
420
list.push_back(str);
421
}
422
return list;
423
}
424
425
uint32_t GetSupportedShaderLanguages() const override {
426
return (uint32_t)ShaderLanguage::GLSL_VULKAN;
427
}
428
uint32_t GetDataFormatSupport(DataFormat fmt) const override;
429
430
PresentMode GetPresentMode() const {
431
switch (vulkan_->GetPresentMode()) {
432
case VK_PRESENT_MODE_FIFO_KHR: return PresentMode::FIFO;
433
case VK_PRESENT_MODE_IMMEDIATE_KHR: return PresentMode::IMMEDIATE;
434
case VK_PRESENT_MODE_MAILBOX_KHR: return PresentMode::MAILBOX;
435
default: return PresentMode::FIFO;
436
}
437
}
438
439
DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) override;
440
BlendState *CreateBlendState(const BlendStateDesc &desc) override;
441
InputLayout *CreateInputLayout(const InputLayoutDesc &desc) override;
442
SamplerState *CreateSamplerState(const SamplerStateDesc &desc) override;
443
RasterState *CreateRasterState(const RasterStateDesc &desc) override;
444
Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) override;
445
ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) override;
446
447
Texture *CreateTexture(const TextureDesc &desc) override;
448
Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override;
449
Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;
450
451
void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;
452
void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;
453
454
void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) override;
455
bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) override;
456
bool CopyFramebufferToMemory(Framebuffer *src, Aspect aspects, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) override;
457
DataFormat PreferredFramebufferReadbackFormat(Framebuffer *src) override;
458
459
// These functions should be self explanatory.
460
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
461
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, Aspect channelBit, int layer) override;
462
463
void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;
464
465
void SetScissorRect(int left, int top, int width, int height) override;
466
void SetViewport(const Viewport &viewport) override;
467
void SetBlendFactor(float color[4]) override;
468
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override;
469
470
void BindSamplerStates(int start, int count, SamplerState **state) override;
471
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
472
void BindNativeTexture(int sampler, void *nativeTexture) override;
473
474
void BindPipeline(Pipeline *pipeline) override {
475
curPipeline_ = (VKPipeline *)pipeline;
476
}
477
478
void BindVertexBuffer(Buffer *vertexBuffer, int offset) override {
479
curVBuffer_ = (VKBuffer *)vertexBuffer;
480
curVBufferOffset_ = offset;
481
}
482
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
483
curIBuffer_ = (VKBuffer *)indexBuffer;
484
curIBufferOffset_ = offset;
485
}
486
487
void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;
488
489
// TODO: Add more sophisticated draws.
490
void Draw(int vertexCount, int offset) override;
491
void DrawIndexed(int vertexCount, int offset) override;
492
void DrawUP(const void *vdata, int vertexCount) override;
493
void DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) override;
494
// Specialized for quick IMGUI drawing.
495
void DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw>, const void *dynUniforms, size_t size) override;
496
497
void BindCurrentPipeline();
498
void ApplyDynamicState();
499
500
void Clear(Aspect aspects, uint32_t colorval, float depthVal, int stencilVal) override;
501
502
void BeginFrame(DebugFlags debugFlags) override;
503
void EndFrame() override;
504
505
void Present(PresentMode presentMode) override;
506
PresentMode GetCurrentPresentMode() const override {
507
switch (vulkan_->GetPresentMode()) {
508
case VK_PRESENT_MODE_IMMEDIATE_KHR:
509
return PresentMode::IMMEDIATE;
510
case VK_PRESENT_MODE_MAILBOX_KHR:
511
return PresentMode::MAILBOX;
512
case VK_PRESENT_MODE_FIFO_KHR:
513
case VK_PRESENT_MODE_FIFO_RELAXED_KHR:
514
case VK_PRESENT_MODE_FIFO_LATEST_READY_KHR:
515
default:
516
return PresentMode::FIFO;
517
}
518
}
519
520
int GetFrameCount() override {
521
return frameCount_;
522
}
523
524
void FlushState() override {}
525
526
void ResetStats() override {
527
renderManager_.ResetStats();
528
}
529
void StopThreads() override {
530
renderManager_.StopThreads();
531
}
532
533
void StartThreads() override {
534
renderManager_.StartThreads();
535
}
536
537
538
std::string GetInfoString(InfoField info) const override {
539
// TODO: Make these actually query the right information
540
switch (info) {
541
case InfoField::APINAME: return "Vulkan";
542
case InfoField::VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties().properties.deviceName;
543
case InfoField::VENDOR: return VulkanVendorString(vulkan_->GetPhysicalDeviceProperties().properties.vendorID);
544
case InfoField::DRIVER: return FormatDriverVersion(vulkan_->GetPhysicalDeviceProperties().properties);
545
case InfoField::SHADELANGVERSION: return "N/A";;
546
case InfoField::APIVERSION: return FormatAPIVersion(vulkan_->InstanceApiVersion());
547
case InfoField::DEVICE_API_VERSION: return FormatAPIVersion(vulkan_->DeviceApiVersion());
548
default: return "?";
549
}
550
}
551
552
void BindDescriptors(VkBuffer buffer, PackedDescriptor descriptors[4]);
553
554
std::vector<std::string> GetFeatureList() const override;
555
std::vector<std::string> GetExtensionList(bool device, bool enabledOnly) const override;
556
557
uint64_t GetNativeObject(NativeObject obj, void *srcObject) override;
558
559
void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;
560
561
void Invalidate(InvalidationFlags flags) override;
562
563
void InvalidateFramebuffer(FBInvalidationStage stage, Aspect aspects) override;
564
565
void SetInvalidationCallback(InvalidationCallback callback) override {
566
renderManager_.SetInvalidationCallback(callback);
567
}
568
569
std::string GetGpuProfileString() const override {
570
return renderManager_.GetGpuProfileString();
571
}
572
573
private:
574
VulkanTexture *GetNullTexture();
575
VulkanContext *vulkan_ = nullptr;
576
577
int frameCount_ = 0;
578
VulkanRenderManager renderManager_;
579
580
VulkanTexture *nullTexture_ = nullptr;
581
582
AutoRef<VKPipeline> curPipeline_;
583
AutoRef<VKBuffer> curVBuffer_;
584
int curVBufferOffset_ = 0;
585
AutoRef<VKBuffer> curIBuffer_;
586
int curIBufferOffset_ = 0;
587
588
VKRPipelineLayout *pipelineLayout_ = nullptr;
589
VkPipelineCache pipelineCache_ = VK_NULL_HANDLE;
590
AutoRef<VKFramebuffer> curFramebuffer_;
591
592
VkDevice device_;
593
594
enum {
595
MAX_FRAME_COMMAND_BUFFERS = 256,
596
};
597
AutoRef<VKTexture> boundTextures_[MAX_BOUND_TEXTURES];
598
AutoRef<VKSamplerState> boundSamplers_[MAX_BOUND_TEXTURES];
599
VkImageView boundImageView_[MAX_BOUND_TEXTURES]{};
600
TextureBindFlags boundTextureFlags_[MAX_BOUND_TEXTURES]{};
601
602
VulkanPushPool *push_ = nullptr;
603
604
DeviceCaps caps_{};
605
606
uint8_t stencilRef_ = 0;
607
uint8_t stencilWriteMask_ = 0xFF;
608
uint8_t stencilCompareMask_ = 0xFF;
609
};
610
611
// Bits per pixel, not bytes.
612
// VERY incomplete!
613
static int GetBpp(VkFormat format) {
614
switch (format) {
615
case VK_FORMAT_R32_SFLOAT:
616
case VK_FORMAT_R8G8B8A8_UNORM:
617
case VK_FORMAT_B8G8R8A8_UNORM:
618
return 32;
619
case VK_FORMAT_R8_UNORM:
620
case VK_FORMAT_S8_UINT:
621
return 8;
622
case VK_FORMAT_R8G8_UNORM:
623
case VK_FORMAT_R16_SFLOAT:
624
case VK_FORMAT_R16_UNORM:
625
return 16;
626
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
627
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
628
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
629
case VK_FORMAT_R5G6B5_UNORM_PACK16:
630
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
631
case VK_FORMAT_B5G6R5_UNORM_PACK16:
632
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
633
return 16;
634
case VK_FORMAT_D24_UNORM_S8_UINT:
635
return 32;
636
case VK_FORMAT_D16_UNORM:
637
return 16;
638
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
639
return 4;
640
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
641
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
642
return 8;
643
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
644
return 8;
645
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
646
return 4;
647
case VK_FORMAT_BC2_UNORM_BLOCK:
648
case VK_FORMAT_BC3_UNORM_BLOCK:
649
case VK_FORMAT_BC4_UNORM_BLOCK:
650
case VK_FORMAT_BC5_UNORM_BLOCK:
651
case VK_FORMAT_BC7_UNORM_BLOCK:
652
return 8;
653
default:
654
return 0;
655
}
656
}
657
658
static VkFormat DataFormatToVulkan(DataFormat format) {
659
switch (format) {
660
case DataFormat::D16: return VK_FORMAT_D16_UNORM;
661
case DataFormat::D16_S8: return VK_FORMAT_D16_UNORM_S8_UINT;
662
case DataFormat::D24_S8: return VK_FORMAT_D24_UNORM_S8_UINT;
663
case DataFormat::D32F: return VK_FORMAT_D32_SFLOAT;
664
case DataFormat::D32F_S8: return VK_FORMAT_D32_SFLOAT_S8_UINT;
665
case DataFormat::S8: return VK_FORMAT_S8_UINT;
666
667
case DataFormat::R16_UNORM: return VK_FORMAT_R16_UNORM;
668
669
case DataFormat::R16_FLOAT: return VK_FORMAT_R16_SFLOAT;
670
case DataFormat::R16G16_FLOAT: return VK_FORMAT_R16G16_SFLOAT;
671
case DataFormat::R16G16B16A16_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT;
672
case DataFormat::R8_UNORM: return VK_FORMAT_R8_UNORM;
673
case DataFormat::R8G8_UNORM: return VK_FORMAT_R8G8_UNORM;
674
case DataFormat::R8G8B8_UNORM: return VK_FORMAT_R8G8B8_UNORM;
675
case DataFormat::R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
676
case DataFormat::R4G4_UNORM_PACK8: return VK_FORMAT_R4G4_UNORM_PACK8;
677
678
// Note: A4R4G4B4_UNORM_PACK16 is not supported.
679
case DataFormat::R4G4B4A4_UNORM_PACK16: return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
680
case DataFormat::B4G4R4A4_UNORM_PACK16: return VK_FORMAT_B4G4R4A4_UNORM_PACK16;
681
case DataFormat::R5G5B5A1_UNORM_PACK16: return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
682
case DataFormat::B5G5R5A1_UNORM_PACK16: return VK_FORMAT_B5G5R5A1_UNORM_PACK16;
683
case DataFormat::R5G6B5_UNORM_PACK16: return VK_FORMAT_R5G6B5_UNORM_PACK16;
684
case DataFormat::B5G6R5_UNORM_PACK16: return VK_FORMAT_B5G6R5_UNORM_PACK16;
685
case DataFormat::A1R5G5B5_UNORM_PACK16: return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
686
687
case DataFormat::R32_FLOAT: return VK_FORMAT_R32_SFLOAT;
688
case DataFormat::R32G32_FLOAT: return VK_FORMAT_R32G32_SFLOAT;
689
case DataFormat::R32G32B32_FLOAT: return VK_FORMAT_R32G32B32_SFLOAT;
690
case DataFormat::R32G32B32A32_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT;
691
692
case DataFormat::BC1_RGBA_UNORM_BLOCK: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
693
case DataFormat::BC2_UNORM_BLOCK: return VK_FORMAT_BC2_UNORM_BLOCK;
694
case DataFormat::BC3_UNORM_BLOCK: return VK_FORMAT_BC3_UNORM_BLOCK;
695
case DataFormat::BC4_UNORM_BLOCK: return VK_FORMAT_BC4_UNORM_BLOCK;
696
case DataFormat::BC5_UNORM_BLOCK: return VK_FORMAT_BC5_UNORM_BLOCK;
697
case DataFormat::BC7_UNORM_BLOCK: return VK_FORMAT_BC7_UNORM_BLOCK;
698
699
case DataFormat::ETC2_R8G8B8A1_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
700
case DataFormat::ETC2_R8G8B8A8_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
701
case DataFormat::ETC2_R8G8B8_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
702
703
case DataFormat::ASTC_4x4_UNORM_BLOCK: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
704
705
default:
706
return VK_FORMAT_UNDEFINED;
707
}
708
}
709
710
static inline VkSamplerAddressMode AddressModeToVulkan(Draw::TextureAddressMode mode) {
711
switch (mode) {
712
case TextureAddressMode::CLAMP_TO_BORDER: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
713
case TextureAddressMode::CLAMP_TO_EDGE: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
714
case TextureAddressMode::REPEAT_MIRROR: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
715
default:
716
case TextureAddressMode::REPEAT: return VK_SAMPLER_ADDRESS_MODE_REPEAT;
717
}
718
}
719
720
VulkanTexture *VKContext::GetNullTexture() {
721
if (!nullTexture_) {
722
VkCommandBuffer cmdInit = renderManager_.GetInitCmd();
723
nullTexture_ = new VulkanTexture(vulkan_, "Null");
724
int w = 8;
725
int h = 8;
726
VulkanBarrierBatch barrier;
727
nullTexture_->CreateDirect(w, h, 1, 1, VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
728
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, &barrier);
729
barrier.Flush(cmdInit);
730
uint32_t bindOffset;
731
VkBuffer bindBuf;
732
uint32_t *data = (uint32_t *)push_->Allocate(w * h * 4, 4, &bindBuf, &bindOffset);
733
_assert_(data != nullptr);
734
for (int y = 0; y < h; y++) {
735
for (int x = 0; x < w; x++) {
736
// data[y*w + x] = ((x ^ y) & 1) ? 0xFF808080 : 0xFF000000; // gray/black checkerboard
737
data[y*w + x] = 0; // black
738
}
739
}
740
TextureCopyBatch batch;
741
nullTexture_->CopyBufferToMipLevel(cmdInit, &batch, 0, w, h, 0, bindBuf, bindOffset, w);
742
nullTexture_->FinishCopyBatch(cmdInit, &batch);
743
nullTexture_->EndCreate(cmdInit, false, VK_PIPELINE_STAGE_TRANSFER_BIT);
744
}
745
return nullTexture_;
746
}
747
748
class VKSamplerState : public SamplerState {
749
public:
750
VKSamplerState(VulkanContext *vulkan, const SamplerStateDesc &desc) : vulkan_(vulkan) {
751
VkSamplerCreateInfo s = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
752
s.addressModeU = AddressModeToVulkan(desc.wrapU);
753
s.addressModeV = AddressModeToVulkan(desc.wrapV);
754
s.addressModeW = AddressModeToVulkan(desc.wrapW);
755
s.anisotropyEnable = desc.maxAniso > 1.0f;
756
s.maxAnisotropy = desc.maxAniso;
757
s.magFilter = desc.magFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
758
s.minFilter = desc.minFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
759
s.mipmapMode = desc.mipFilter == TextureFilter::LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
760
s.maxLod = VK_LOD_CLAMP_NONE;
761
VkResult res = vkCreateSampler(vulkan_->GetDevice(), &s, nullptr, &sampler_);
762
_assert_(VK_SUCCESS == res);
763
}
764
~VKSamplerState() {
765
vulkan_->Delete().QueueDeleteSampler(sampler_);
766
}
767
768
VkSampler GetSampler() { return sampler_; }
769
770
private:
771
VulkanContext *vulkan_;
772
VkSampler sampler_;
773
};
774
775
SamplerState *VKContext::CreateSamplerState(const SamplerStateDesc &desc) {
776
return new VKSamplerState(vulkan_, desc);
777
}
778
779
RasterState *VKContext::CreateRasterState(const RasterStateDesc &desc) {
780
return new VKRasterState(desc);
781
}
782
783
void VKContext::BindSamplerStates(int start, int count, SamplerState **state) {
784
_assert_(start + count <= MAX_BOUND_TEXTURES);
785
for (int i = start; i < start + count; i++) {
786
boundSamplers_[i] = (VKSamplerState *)state[i - start];
787
}
788
}
789
790
enum class TextureState {
791
UNINITIALIZED,
792
STAGED,
793
INITIALIZED,
794
PENDING_DESTRUCTION,
795
};
796
797
bool VKTexture::Create(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const TextureDesc &desc) {
798
// Zero-sized textures not allowed.
799
_assert_(desc.width * desc.height * desc.depth > 0); // remember to set depth to 1!
800
if (desc.width * desc.height * desc.depth <= 0) {
801
ERROR_LOG(Log::G3D, "Bad texture dimensions %dx%dx%d", desc.width, desc.height, desc.depth);
802
return false;
803
}
804
_dbg_assert_(pushBuffer);
805
format_ = desc.format;
806
mipLevels_ = desc.mipLevels;
807
width_ = desc.width;
808
height_ = desc.height;
809
depth_ = desc.depth;
810
vkTex_ = new VulkanTexture(vulkan_, desc.tag);
811
VkFormat vulkanFormat = DataFormatToVulkan(format_);
812
int usageBits = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
813
if (mipLevels_ > (int)desc.initData.size()) {
814
// Gonna have to generate some, which requires TRANSFER_SRC
815
usageBits |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
816
}
817
818
static const VkComponentMapping r8AsAlpha[4] = { {VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_ONE, VK_COMPONENT_SWIZZLE_R} };
819
static const VkComponentMapping r8AsColor[4] = { {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE} };
820
static const VkComponentMapping r8AsPremulAlpha[4] = { {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R} };
821
822
const VkComponentMapping *swizzle = nullptr;
823
switch (desc.swizzle) {
824
case TextureSwizzle::R8_AS_ALPHA: swizzle = r8AsAlpha; break;
825
case TextureSwizzle::R8_AS_GRAYSCALE: swizzle = r8AsColor; break;
826
case TextureSwizzle::R8_AS_PREMUL_ALPHA: swizzle = r8AsPremulAlpha; break;
827
case TextureSwizzle::DEFAULT:
828
break;
829
}
830
VulkanBarrierBatch barrier;
831
if (!vkTex_->CreateDirect(width_, height_, 1, mipLevels_, vulkanFormat, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, usageBits, &barrier, swizzle)) {
832
ERROR_LOG(Log::G3D, "Failed to create VulkanTexture: %dx%dx%d fmt %d, %d levels", width_, height_, depth_, (int)vulkanFormat, mipLevels_);
833
return false;
834
}
835
barrier.Flush(cmd);
836
VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
837
if (desc.initData.size()) {
838
UpdateInternal(cmd, pushBuffer, desc.initData.data(), desc.initDataCallback, (int)desc.initData.size());
839
// Generate the rest of the mips automatically.
840
if ((int)desc.initData.size() < mipLevels_) {
841
vkTex_->GenerateMips(cmd, (int)desc.initData.size(), false);
842
layout = VK_IMAGE_LAYOUT_GENERAL;
843
}
844
}
845
vkTex_->EndCreate(cmd, false, VK_PIPELINE_STAGE_TRANSFER_BIT, layout);
846
return true;
847
}
848
849
void VKTexture::Update(VkCommandBuffer cmd, VulkanBarrierBatch *postBarriers, VulkanPushPool *pushBuffer, const uint8_t * const *data, TextureCallback initDataCallback, int numLevels) {
850
// Before we can use UpdateInternal, we need to transition the image to the same state as after CreateDirect,
851
// making it ready for writing.
852
vkTex_->PrepareForTransferDst(cmd, numLevels);
853
UpdateInternal(cmd, pushBuffer, data, initDataCallback, numLevels);
854
vkTex_->RestoreAfterTransferDst(numLevels, postBarriers);
855
}
856
857
void VKTexture::UpdateInternal(VkCommandBuffer cmd, VulkanPushPool *pushBuffer, const uint8_t * const *data, TextureCallback initDataCallback, int numLevels) {
858
int w = width_;
859
int h = height_;
860
int d = depth_;
861
VkFormat vulkanFormat = DataFormatToVulkan(format_);
862
int bpp = GetBpp(vulkanFormat);
863
_dbg_assert_(bpp != 0);
864
int bytesPerPixel = bpp / 8;
865
TextureCopyBatch batch;
866
batch.reserve(numLevels);
867
for (int i = 0; i < numLevels; i++) {
868
uint32_t offset;
869
VkBuffer buf;
870
size_t size = w * h * d * bytesPerPixel;
871
uint8_t *dest = (uint8_t *)pushBuffer->Allocate(size, 16, &buf, &offset);
872
if (initDataCallback) {
873
_assert_(dest != nullptr);
874
if (!initDataCallback(dest, data[i], w, h, d, w * bytesPerPixel, h * w * bytesPerPixel)) {
875
memcpy(dest, data[i], size);
876
}
877
} else {
878
memcpy(dest, data[i], size);
879
}
880
vkTex_->CopyBufferToMipLevel(cmd, &batch, i, w, h, 0, buf, offset, w);
881
w = (w + 1) / 2;
882
h = (h + 1) / 2;
883
d = (d + 1) / 2;
884
}
885
vkTex_->FinishCopyBatch(cmd, &batch);
886
}
887
888
static DataFormat DataFormatFromVulkanDepth(VkFormat fmt) {
889
switch (fmt) {
890
case VK_FORMAT_D24_UNORM_S8_UINT:
891
return DataFormat::D24_S8;
892
case VK_FORMAT_D16_UNORM:
893
return DataFormat::D16;
894
case VK_FORMAT_D32_SFLOAT:
895
return DataFormat::D32F;
896
case VK_FORMAT_D32_SFLOAT_S8_UINT:
897
return DataFormat::D32F_S8;
898
case VK_FORMAT_D16_UNORM_S8_UINT:
899
return DataFormat::D16_S8;
900
default:
901
break;
902
}
903
904
return DataFormat::UNDEFINED;
905
}
906
907
VKContext::VKContext(VulkanContext *vulkan, bool useRenderThread)
908
: vulkan_(vulkan), renderManager_(vulkan, useRenderThread, frameTimeHistory_) {
909
shaderLanguageDesc_.Init(GLSL_VULKAN);
910
911
// Make sure that the surface has been initialized.
912
_dbg_assert_(vulkan->GetAvailablePresentModes().size() > 0);
913
914
caps_.coordConvention = CoordConvention::Vulkan;
915
caps_.setMaxFrameLatencySupported = true;
916
caps_.anisoSupported = vulkan->GetDeviceFeatures().enabled.standard.samplerAnisotropy != 0;
917
caps_.geometryShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.geometryShader != 0;
918
caps_.tesselationShaderSupported = vulkan->GetDeviceFeatures().enabled.standard.tessellationShader != 0;
919
caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.standard.dualSrcBlend != 0;
920
caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.standard.depthClamp != 0;
921
922
caps_.maxTextureSize = vulkan->GetPhysicalDeviceProperties().properties.limits.maxImageDimension2D;
923
caps_.maxClipPlanes = vulkan->GetPhysicalDeviceProperties().properties.limits.maxClipDistances;
924
925
// Comment out these two to test geometry shader culling on any geometry shader-supporting hardware.
926
caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderClipDistance != 0;
927
caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.standard.shaderCullDistance != 0;
928
929
caps_.framebufferBlitSupported = true;
930
caps_.framebufferCopySupported = true;
931
caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat;
932
caps_.framebufferStencilBlitSupported = caps_.framebufferDepthBlitSupported;
933
caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case.
934
caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case.
935
// This doesn't affect what depth/stencil format is actually used, see VulkanQueueRunner.
936
caps_.preferredDepthBufferFormat = DataFormatFromVulkanDepth(vulkan->GetDeviceInfo().preferredDepthStencilFormat);
937
caps_.texture3DSupported = true;
938
caps_.textureDepthSupported = true;
939
caps_.fragmentShaderInt32Supported = true;
940
caps_.textureNPOTFullySupported = true;
941
caps_.fragmentShaderDepthWriteSupported = true;
942
caps_.fragmentShaderStencilWriteSupported = vulkan->Extensions().EXT_shader_stencil_export;
943
caps_.blendMinMaxSupported = true;
944
caps_.logicOpSupported = vulkan->GetDeviceFeatures().enabled.standard.logicOp != 0;
945
caps_.multiViewSupported = vulkan->GetDeviceFeatures().enabled.multiview.multiview != 0;
946
caps_.sampleRateShadingSupported = vulkan->GetDeviceFeatures().enabled.standard.sampleRateShading != 0;
947
caps_.textureSwizzleSupported = true;
948
949
// Note that it must also be enabled on the pipelines (which we do).
950
caps_.provokingVertexLast = vulkan->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast;
951
952
// Present mode stuff
953
caps_.presentMaxInterval = 1;
954
caps_.presentInstantModeChange = false; // TODO: Fix this with some work in VulkanContext
955
caps_.presentModesSupported = (PresentMode)0;
956
957
for (auto mode : vulkan->GetAvailablePresentModes()) {
958
switch (mode) {
959
case VK_PRESENT_MODE_FIFO_KHR: caps_.presentModesSupported |= PresentMode::FIFO; break;
960
case VK_PRESENT_MODE_IMMEDIATE_KHR: caps_.presentModesSupported |= PresentMode::IMMEDIATE; break;
961
case VK_PRESENT_MODE_MAILBOX_KHR: caps_.presentModesSupported |= PresentMode::MAILBOX; break;
962
default: break; // Ignore any other modes.
963
}
964
}
965
966
const auto &limits = vulkan->GetPhysicalDeviceProperties().properties.limits;
967
968
auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties;
969
970
switch (deviceProps.vendorID) {
971
case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break;
972
case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break;
973
case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break;
974
case VULKAN_VENDOR_NVIDIA: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break;
975
case VULKAN_VENDOR_QUALCOMM: caps_.vendor = GPUVendor::VENDOR_QUALCOMM; break;
976
case VULKAN_VENDOR_INTEL: caps_.vendor = GPUVendor::VENDOR_INTEL; break;
977
case VULKAN_VENDOR_APPLE: caps_.vendor = GPUVendor::VENDOR_APPLE; break;
978
case VULKAN_VENDOR_MESA: caps_.vendor = GPUVendor::VENDOR_MESA; break;
979
default:
980
WARN_LOG(Log::G3D, "Unknown vendor ID %08x", deviceProps.vendorID);
981
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
982
break;
983
}
984
985
switch (caps_.vendor) {
986
case GPUVendor::VENDOR_ARM:
987
case GPUVendor::VENDOR_IMGTEC:
988
case GPUVendor::VENDOR_QUALCOMM:
989
caps_.isTilingGPU = true;
990
break;
991
default:
992
caps_.isTilingGPU = false;
993
break;
994
}
995
996
if (caps_.vendor == GPUVendor::VENDOR_IMGTEC) {
997
// Enable some things that cut down pipeline counts but may have other costs.
998
caps_.verySlowShaderCompiler = true;
999
}
1000
1001
// VkSampleCountFlagBits is arranged correctly for our purposes.
1002
// Only support MSAA levels that have support for all three of color, depth, stencil.
1003
1004
bool multisampleAllowed = true;
1005
1006
caps_.deviceID = deviceProps.deviceID;
1007
1008
if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) {
1009
if (caps_.deviceID < 0x6000000) { // On sub 6xx series GPUs, disallow multisample.
1010
INFO_LOG(Log::G3D, "Multisampling was disabled due to old driver version (Adreno)");
1011
multisampleAllowed = false;
1012
}
1013
1014
// Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off.
1015
// See: https://github.com/hrydgard/ppsspp/pull/11684
1016
if (deviceProps.deviceID >= 0x05000000 && deviceProps.deviceID < 0x06000000) {
1017
if (deviceProps.driverVersion < 0x80180000) {
1018
bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_ADRENO);
1019
}
1020
}
1021
// Color write mask not masking write in certain scenarios with a depth test, see #10421.
1022
// Known still present on driver 0x80180000 and Adreno 5xx (possibly more.)
1023
// Known working on driver 0x801EA000 and Adreno 620.
1024
if (deviceProps.driverVersion < 0x801EA000 || deviceProps.deviceID < 0x06000000)
1025
bugs_.Infest(Bugs::COLORWRITEMASK_BROKEN_WITH_DEPTHTEST);
1026
1027
// Trying to follow all the rules in https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies
1028
// and https://registry.khronos.org/vulkan/specs/1.3/html/vkspec.html#renderpass-feedbackloop, but still it doesn't
1029
// quite work - artifacts on triangle boundaries on Adreno.
1030
bugs_.Infest(Bugs::SUBPASS_FEEDBACK_BROKEN);
1031
} else if (caps_.vendor == GPUVendor::VENDOR_AMD) {
1032
// See issue #10074, and also #10065 (AMD) and #10109 for the choice of the driver version to check for.
1033
if (deviceProps.driverVersion < 0x00407000) {
1034
bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN);
1035
}
1036
} else if (caps_.vendor == GPUVendor::VENDOR_INTEL) {
1037
// Workaround for Intel driver bug. TODO: Re-enable after some driver version
1038
bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN);
1039
} else if (caps_.vendor == GPUVendor::VENDOR_ARM) {
1040
// Really old Vulkan drivers for Mali didn't have proper versions. We try to detect that (can't be 100% but pretty good).
1041
bool isOldVersion = IsHashMaliDriverVersion(deviceProps);
1042
1043
int majorVersion = VK_API_VERSION_MAJOR(deviceProps.driverVersion);
1044
1045
// These GPUs (up to some certain hardware version?) have a bug where draws where gl_Position.w == .z
1046
// corrupt the depth buffer. This is easily worked around by simply scaling Z down a tiny bit when this case
1047
// is detected. See: https://github.com/hrydgard/ppsspp/issues/11937
1048
bugs_.Infest(Bugs::EQUAL_WZ_CORRUPTS_DEPTH);
1049
1050
// Nearly identical to the the Adreno bug, see #13833 (Midnight Club map broken) and other issues.
1051
// It has the additional caveat that combining depth writes with NEVER depth tests crashes the driver.
1052
// Reported fixed in major version 40 - let's add a check once confirmed.
1053
bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL_MALI);
1054
1055
// This started in driver 31 or 32, fixed in 40 - let's add a check once confirmed.
1056
if (majorVersion >= 32) {
1057
bugs_.Infest(Bugs::MALI_CONSTANT_LOAD_BUG); // See issue #15661
1058
}
1059
1060
if (deviceProps.driverVersion == 0xaa9c4b29) {
1061
bugs_.Infest(Bugs::EMPTY_RENDERPASS_BROKEN_MALI);
1062
}
1063
1064
// Older ARM devices have very slow geometry shaders, not worth using. At least before 15.
1065
// Also seen to cause weird issues on 18, so let's lump it in.
1066
if (majorVersion <= 18 || isOldVersion) {
1067
bugs_.Infest(Bugs::GEOMETRY_SHADERS_SLOW_OR_BROKEN);
1068
}
1069
1070
// Attempt to workaround #17386
1071
if (isOldVersion) {
1072
if (!strcmp(deviceProps.deviceName, "Mali-T880") ||
1073
!strcmp(deviceProps.deviceName, "Mali-T860") ||
1074
!strcmp(deviceProps.deviceName, "Mali-T830")) {
1075
bugs_.Infest(Bugs::UNIFORM_INDEXING_BROKEN);
1076
}
1077
}
1078
1079
if (isOldVersion) {
1080
// Very rough heuristic.
1081
multisampleAllowed = false;
1082
}
1083
} else if (caps_.vendor == GPUVendor::VENDOR_IMGTEC) {
1084
// Not sure about driver versions, so let's just ban, impact is tiny.
1085
bugs_.Infest(Bugs::PVR_BAD_16BIT_TEXFORMATS);
1086
}
1087
1088
if (!vulkan->Extensions().KHR_depth_stencil_resolve) {
1089
INFO_LOG(Log::G3D, "KHR_depth_stencil_resolve not supported, disabling multisampling");
1090
multisampleAllowed = false;
1091
}
1092
1093
if (!vulkan->Extensions().KHR_create_renderpass2) {
1094
WARN_LOG(Log::G3D, "KHR_create_renderpass2 not supported, disabling multisampling");
1095
multisampleAllowed = false;
1096
} else {
1097
_dbg_assert_(vkCreateRenderPass2 != nullptr);
1098
}
1099
1100
// We limit multisampling functionality to reasonably recent and known-good tiling GPUs.
1101
if (multisampleAllowed) {
1102
// Check for depth stencil resolve. Without it, depth textures won't work, and we don't want that mess
1103
// of compatibility reports, so we'll just disable multisampling in this case for now.
1104
// There are potential workarounds for devices that don't support it, but those are nearly non-existent now.
1105
const auto &resolveProperties = vulkan->GetPhysicalDeviceProperties().depthStencilResolve;
1106
if (((resolveProperties.supportedDepthResolveModes & resolveProperties.supportedStencilResolveModes) & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) {
1107
caps_.multiSampleLevelsMask = (limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts & limits.framebufferStencilSampleCounts);
1108
INFO_LOG(Log::G3D, "Multisample levels mask: %d", caps_.multiSampleLevelsMask);
1109
} else {
1110
INFO_LOG(Log::G3D, "Not enough depth/stencil resolve modes supported, disabling multisampling. Color: %d Depth: %d Stencil: %d",
1111
limits.framebufferColorSampleCounts, limits.framebufferDepthSampleCounts, limits.framebufferStencilSampleCounts);
1112
caps_.multiSampleLevelsMask = 1;
1113
}
1114
} else {
1115
caps_.multiSampleLevelsMask = 1;
1116
}
1117
1118
// Vulkan can support this through input attachments and various extensions, but not worth
1119
// the trouble.
1120
caps_.framebufferFetchSupported = false;
1121
1122
device_ = vulkan->GetDevice();
1123
1124
VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1125
push_ = new VulkanPushPool(vulkan_, "pushBuffer", 4 * 1024 * 1024, usage);
1126
1127
// binding 0 - uniform data
1128
// binding 1 - combined sampler/image 0
1129
// binding 2 - combined sampler/image 1
1130
// ...etc
1131
BindingType bindings[MAX_BOUND_TEXTURES + 1];
1132
bindings[0] = BindingType::UNIFORM_BUFFER_DYNAMIC_ALL;
1133
for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) {
1134
bindings[1 + i] = BindingType::COMBINED_IMAGE_SAMPLER;
1135
}
1136
pipelineLayout_ = renderManager_.CreatePipelineLayout(bindings, ARRAY_SIZE(bindings), caps_.geometryShaderSupported, "thin3d_layout");
1137
1138
VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO };
1139
VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_);
1140
_assert_(VK_SUCCESS == res);
1141
}
1142
1143
VKContext::~VKContext() {
1144
DestroyPresets();
1145
1146
delete nullTexture_;
1147
push_->Destroy();
1148
delete push_;
1149
renderManager_.DestroyPipelineLayout(pipelineLayout_);
1150
vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_);
1151
}
1152
1153
void VKContext::BeginFrame(DebugFlags debugFlags) {
1154
renderManager_.BeginFrame(debugFlags & DebugFlags::PROFILE_TIMESTAMPS, debugFlags & DebugFlags::PROFILE_SCOPES);
1155
push_->BeginFrame();
1156
}
1157
1158
void VKContext::EndFrame() {
1159
// Do all the work to submit the command buffers etc.
1160
renderManager_.Finish();
1161
// Unbind stuff, to avoid accidentally relying on it across frames (and provide some protection against forgotten unbinds of deleted things).
1162
Invalidate(InvalidationFlags::CACHED_RENDER_STATE);
1163
}
1164
1165
void VKContext::Present(PresentMode presentMode) {
1166
renderManager_.Present();
1167
frameCount_++;
1168
}
1169
1170
void VKContext::Invalidate(InvalidationFlags flags) {
1171
if (flags & InvalidationFlags::CACHED_RENDER_STATE) {
1172
curPipeline_ = nullptr;
1173
1174
for (auto &view : boundImageView_) {
1175
view = VK_NULL_HANDLE;
1176
}
1177
for (auto &sampler : boundSamplers_) {
1178
sampler = nullptr;
1179
}
1180
for (auto &texture : boundTextures_) {
1181
texture = nullptr;
1182
}
1183
}
1184
}
1185
1186
void VKContext::BindDescriptors(VkBuffer buf, PackedDescriptor descriptors[4]) {
1187
descriptors[0].buffer.buffer = buf;
1188
descriptors[0].buffer.offset = 0; // dynamic
1189
descriptors[0].buffer.range = curPipeline_->GetUBOSize();
1190
1191
for (int i = 0; i < MAX_BOUND_TEXTURES; ++i) {
1192
VkImageView view;
1193
VkSampler sampler;
1194
if (boundTextures_[i]) {
1195
view = (boundTextureFlags_[i] & TextureBindFlags::VULKAN_BIND_ARRAY) ? boundTextures_[i]->GetImageArrayView() : boundTextures_[i]->GetImageView();
1196
} else {
1197
view = boundImageView_[i];
1198
}
1199
sampler = boundSamplers_[i] ? boundSamplers_[i]->GetSampler() : VK_NULL_HANDLE;
1200
1201
if (view && sampler) {
1202
descriptors[i + 1].image.view = view;
1203
descriptors[i + 1].image.sampler = sampler;
1204
} else {
1205
descriptors[i + 1].image.view = VK_NULL_HANDLE;
1206
descriptors[i + 1].image.sampler = VK_NULL_HANDLE;
1207
}
1208
}
1209
}
1210
1211
Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {
1212
VKInputLayout *input = (VKInputLayout *)desc.inputLayout;
1213
VKBlendState *blend = (VKBlendState *)desc.blend;
1214
VKDepthStencilState *depth = (VKDepthStencilState *)desc.depthStencil;
1215
VKRasterState *raster = (VKRasterState *)desc.raster;
1216
1217
PipelineFlags pipelineFlags = (PipelineFlags)0;
1218
if (depth->info.depthTestEnable || depth->info.stencilTestEnable) {
1219
pipelineFlags |= PipelineFlags::USES_DEPTH_STENCIL;
1220
}
1221
// TODO: We need code to set USES_BLEND_CONSTANT here too, if we're ever gonna use those in thin3d code.
1222
1223
VKPipeline *pipeline = new VKPipeline(vulkan_, desc.uniformDesc ? desc.uniformDesc->uniformBufferSize : 16 * sizeof(float), pipelineFlags, tag);
1224
1225
VKRGraphicsPipelineDesc &gDesc = *pipeline->vkrDesc;
1226
1227
std::vector<VkPipelineShaderStageCreateInfo> stages;
1228
stages.resize(desc.shaders.size());
1229
1230
for (auto &iter : desc.shaders) {
1231
VKShaderModule *vkshader = (VKShaderModule *)iter;
1232
if (!iter) {
1233
ERROR_LOG(Log::G3D, "Null shader in pipeline creation");
1234
delete pipeline;
1235
return nullptr;
1236
}
1237
vkshader->AddRef();
1238
pipeline->deps.push_back(vkshader);
1239
if (vkshader->GetStage() == ShaderStage::Vertex) {
1240
gDesc.vertexShader = vkshader->Get();
1241
} else if (vkshader->GetStage() == ShaderStage::Fragment) {
1242
gDesc.fragmentShader = vkshader->Get();
1243
} else {
1244
ERROR_LOG(Log::G3D, "Bad stage");
1245
delete pipeline;
1246
return nullptr;
1247
}
1248
}
1249
1250
_dbg_assert_(input);
1251
_dbg_assert_((int)input->attributes.size() == (int)input->visc.vertexAttributeDescriptionCount);
1252
1253
pipeline->stride = input->binding.stride;
1254
gDesc.ibd = input->binding;
1255
for (size_t i = 0; i < input->attributes.size(); i++) {
1256
gDesc.attrs[i] = input->attributes[i];
1257
}
1258
gDesc.vis.vertexAttributeDescriptionCount = input->visc.vertexAttributeDescriptionCount;
1259
gDesc.vis.vertexBindingDescriptionCount = input->visc.vertexBindingDescriptionCount;
1260
gDesc.vis.pVertexBindingDescriptions = &gDesc.ibd;
1261
gDesc.vis.pVertexAttributeDescriptions = gDesc.attrs;
1262
1263
gDesc.blend0 = blend->attachments[0];
1264
gDesc.cbs = blend->info;
1265
gDesc.cbs.pAttachments = &gDesc.blend0;
1266
1267
gDesc.dss = depth->info;
1268
1269
// Copy bindings from input layout.
1270
gDesc.topology = primToVK[(int)desc.prim];
1271
1272
// We treat the three stencil states as a unit in other places, so let's do that here too.
1273
const VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK };
1274
gDesc.ds.dynamicStateCount = depth->info.stencilTestEnable ? ARRAY_SIZE(dynamics) : 2;
1275
for (size_t i = 0; i < gDesc.ds.dynamicStateCount; i++) {
1276
gDesc.dynamicStates[i] = dynamics[i];
1277
}
1278
gDesc.ds.pDynamicStates = gDesc.dynamicStates;
1279
1280
gDesc.views.viewportCount = 1;
1281
gDesc.views.scissorCount = 1;
1282
gDesc.views.pViewports = nullptr; // dynamic
1283
gDesc.views.pScissors = nullptr; // dynamic
1284
1285
gDesc.pipelineLayout = pipelineLayout_;
1286
1287
raster->ToVulkan(&gDesc.rs);
1288
1289
if (renderManager_.GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
1290
ChainStruct(gDesc.rs, &gDesc.rs_provoking);
1291
gDesc.rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
1292
}
1293
1294
pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, false, tag ? tag : "thin3d");
1295
1296
if (desc.uniformDesc) {
1297
pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize;
1298
}
1299
if (depth->info.stencilTestEnable) {
1300
pipeline->usesStencil = true;
1301
}
1302
return pipeline;
1303
}
1304
1305
void VKContext::SetScissorRect(int left, int top, int width, int height) {
1306
renderManager_.SetScissor(left, top, width, height);
1307
}
1308
1309
void VKContext::SetViewport(const Viewport &viewport) {
1310
// Ignore viewports more than the first.
1311
VkViewport vkViewport;
1312
vkViewport.x = viewport.TopLeftX;
1313
vkViewport.y = viewport.TopLeftY;
1314
vkViewport.width = viewport.Width;
1315
vkViewport.height = viewport.Height;
1316
vkViewport.minDepth = viewport.MinDepth;
1317
vkViewport.maxDepth = viewport.MaxDepth;
1318
renderManager_.SetViewport(vkViewport);
1319
}
1320
1321
void VKContext::SetBlendFactor(float color[4]) {
1322
uint32_t col = Float4ToUint8x4(color);
1323
renderManager_.SetBlendFactor(col);
1324
}
1325
1326
void VKContext::SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) {
1327
if (curPipeline_->usesStencil)
1328
renderManager_.SetStencilParams(writeMask, compareMask, refValue);
1329
stencilRef_ = refValue;
1330
stencilWriteMask_ = writeMask;
1331
stencilCompareMask_ = compareMask;
1332
}
1333
1334
InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
1335
VKInputLayout *vl = new VKInputLayout();
1336
vl->visc = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
1337
vl->visc.flags = 0;
1338
vl->visc.vertexBindingDescriptionCount = 1;
1339
vl->visc.vertexAttributeDescriptionCount = (uint32_t)desc.attributes.size();
1340
vl->attributes.resize(vl->visc.vertexAttributeDescriptionCount);
1341
vl->visc.pVertexBindingDescriptions = &vl->binding;
1342
vl->visc.pVertexAttributeDescriptions = vl->attributes.data();
1343
for (size_t i = 0; i < desc.attributes.size(); i++) {
1344
vl->attributes[i].binding = 0;
1345
vl->attributes[i].format = DataFormatToVulkan(desc.attributes[i].format);
1346
vl->attributes[i].location = desc.attributes[i].location;
1347
vl->attributes[i].offset = desc.attributes[i].offset;
1348
}
1349
vl->binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1350
vl->binding.binding = 0;
1351
vl->binding.stride = desc.stride;
1352
return vl;
1353
}
1354
1355
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
1356
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
1357
if (!push_ || !initCmd) {
1358
// Too early! Fail.
1359
ERROR_LOG(Log::G3D, "Can't create textures before the first frame has started.");
1360
return nullptr;
1361
}
1362
VKTexture *tex = new VKTexture(vulkan_, desc);
1363
if (tex->Create(initCmd, &renderManager_.PostInitBarrier(), push_, desc)) {
1364
return tex;
1365
} else {
1366
ERROR_LOG(Log::G3D, "Failed to create texture");
1367
tex->Release();
1368
return nullptr;
1369
}
1370
}
1371
1372
void VKContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {
1373
VkCommandBuffer initCmd = renderManager_.GetInitCmd();
1374
if (!push_ || !initCmd) {
1375
// Too early! Fail.
1376
ERROR_LOG(Log::G3D, "Can't create textures before the first frame has started.");
1377
return;
1378
}
1379
1380
VKTexture *tex = (VKTexture *)texture;
1381
1382
_dbg_assert_(numLevels <= tex->NumLevels());
1383
tex->Update(initCmd, &renderManager_.PostInitBarrier(), push_, data, initDataCallback, numLevels);
1384
}
1385
1386
static inline void CopySide(VkStencilOpState &dest, const StencilSetup &src) {
1387
dest.compareOp = compToVK[(int)src.compareOp];
1388
dest.failOp = stencilOpToVK[(int)src.failOp];
1389
dest.passOp = stencilOpToVK[(int)src.passOp];
1390
dest.depthFailOp = stencilOpToVK[(int)src.depthFailOp];
1391
}
1392
1393
DepthStencilState *VKContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
1394
VKDepthStencilState *ds = new VKDepthStencilState();
1395
ds->info.depthCompareOp = compToVK[(int)desc.depthCompare];
1396
ds->info.depthTestEnable = desc.depthTestEnabled;
1397
ds->info.depthWriteEnable = desc.depthWriteEnabled;
1398
ds->info.stencilTestEnable = desc.stencilEnabled;
1399
ds->info.depthBoundsTestEnable = false;
1400
if (ds->info.stencilTestEnable) {
1401
CopySide(ds->info.front, desc.stencil);
1402
CopySide(ds->info.back, desc.stencil);
1403
}
1404
return ds;
1405
}
1406
1407
BlendState *VKContext::CreateBlendState(const BlendStateDesc &desc) {
1408
VKBlendState *bs = new VKBlendState();
1409
bs->info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1410
bs->info.attachmentCount = 1;
1411
bs->info.logicOp = logicOpToVK[(int)desc.logicOp];
1412
bs->info.logicOpEnable = desc.logicEnabled;
1413
bs->attachments.resize(1);
1414
bs->attachments[0].blendEnable = desc.enabled;
1415
bs->attachments[0].colorBlendOp = blendEqToVk[(int)desc.eqCol];
1416
bs->attachments[0].alphaBlendOp = blendEqToVk[(int)desc.eqAlpha];
1417
bs->attachments[0].colorWriteMask = desc.colorMask;
1418
bs->attachments[0].dstAlphaBlendFactor = blendFactorToVk[(int)desc.dstAlpha];
1419
bs->attachments[0].dstColorBlendFactor = blendFactorToVk[(int)desc.dstCol];
1420
bs->attachments[0].srcAlphaBlendFactor = blendFactorToVk[(int)desc.srcAlpha];
1421
bs->attachments[0].srcColorBlendFactor = blendFactorToVk[(int)desc.srcCol];
1422
bs->info.pAttachments = bs->attachments.data();
1423
return bs;
1424
}
1425
1426
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
1427
// to avoid synchronization issues.
1428
class VKBuffer : public Buffer {
1429
public:
1430
VKBuffer(size_t size) : dataSize_(size) {
1431
data_ = new uint8_t[size];
1432
}
1433
~VKBuffer() {
1434
delete[] data_;
1435
}
1436
1437
size_t GetSize() const { return dataSize_; }
1438
const uint8_t *GetData() const { return data_; }
1439
1440
uint8_t *data_;
1441
size_t dataSize_;
1442
};
1443
1444
Buffer *VKContext::CreateBuffer(size_t size, uint32_t usageFlags) {
1445
return new VKBuffer(size);
1446
}
1447
1448
void VKContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) {
1449
VKBuffer *buf = (VKBuffer *)buffer;
1450
memcpy(buf->data_ + offset, data, size);
1451
}
1452
1453
void VKContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
1454
_assert_(start + count <= MAX_BOUND_TEXTURES);
1455
for (int i = start; i < start + count; i++) {
1456
_dbg_assert_(i >= 0 && i < MAX_BOUND_TEXTURES);
1457
boundTextures_[i] = static_cast<VKTexture *>(textures[i - start]);
1458
boundTextureFlags_[i] = flags;
1459
if (boundTextures_[i]) {
1460
// If a texture is bound, we set these up in BindDescriptors too.
1461
// But we might need to set the view here anyway so it can be queried using GetNativeObject.
1462
if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) {
1463
boundImageView_[i] = boundTextures_[i]->GetImageArrayView();
1464
} else {
1465
boundImageView_[i] = boundTextures_[i]->GetImageView();
1466
}
1467
} else {
1468
if (flags & TextureBindFlags::VULKAN_BIND_ARRAY) {
1469
boundImageView_[i] = GetNullTexture()->GetImageArrayView();
1470
} else {
1471
boundImageView_[i] = GetNullTexture()->GetImageView();
1472
}
1473
}
1474
}
1475
}
1476
1477
void VKContext::BindNativeTexture(int sampler, void *nativeTexture) {
1478
_dbg_assert_(sampler >= 0 && sampler < MAX_BOUND_TEXTURES);
1479
boundTextures_[sampler] = nullptr;
1480
boundImageView_[sampler] = (VkImageView)nativeTexture;
1481
}
1482
1483
ShaderModule *VKContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t size, const char *tag) {
1484
VKShaderModule *shader = new VKShaderModule(stage, tag);
1485
if (shader->Compile(vulkan_, data, size)) {
1486
return shader;
1487
} else {
1488
ERROR_LOG(Log::G3D, "Failed to compile shader %s:\n%s", tag, (const char *)LineNumberString((const char *)data).c_str());
1489
shader->Release();
1490
return nullptr;
1491
}
1492
}
1493
1494
void VKContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
1495
curPipeline_->SetDynamicUniformData(ub, size);
1496
}
1497
1498
void VKContext::ApplyDynamicState() {
1499
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
1500
if (curPipeline_->usesStencil) {
1501
renderManager_.SetStencilParams(stencilWriteMask_, stencilCompareMask_, stencilRef_);
1502
}
1503
}
1504
1505
void VKContext::Draw(int vertexCount, int offset) {
1506
VKBuffer *vbuf = curVBuffer_;
1507
1508
VkBuffer vulkanVbuf;
1509
VkBuffer vulkanUBObuf;
1510
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
1511
size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), 4, &vulkanVbuf);
1512
1513
BindCurrentPipeline();
1514
ApplyDynamicState();
1515
int descSetIndex;
1516
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
1517
BindDescriptors(vulkanUBObuf, descriptors);
1518
renderManager_.Draw(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffset_, vertexCount, offset);
1519
}
1520
1521
void VKContext::DrawIndexed(int vertexCount, int offset) {
1522
VKBuffer *ibuf = curIBuffer_;
1523
VKBuffer *vbuf = curVBuffer_;
1524
1525
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
1526
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
1527
size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), 4, &vulkanVbuf);
1528
size_t ibBindOffset = push_->Push(ibuf->GetData(), ibuf->GetSize(), 4, &vulkanIbuf);
1529
1530
BindCurrentPipeline();
1531
ApplyDynamicState();
1532
int descSetIndex;
1533
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
1534
BindDescriptors(vulkanUBObuf, descriptors);
1535
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset + curVBufferOffset_, vulkanIbuf, (int)ibBindOffset + offset * sizeof(uint32_t), vertexCount, 1);
1536
}
1537
1538
void VKContext::DrawUP(const void *vdata, int vertexCount) {
1539
_dbg_assert_(vertexCount >= 0);
1540
if (vertexCount <= 0) {
1541
return;
1542
}
1543
1544
VkBuffer vulkanVbuf, vulkanUBObuf;
1545
size_t dataSize = vertexCount * curPipeline_->stride;
1546
uint32_t vbBindOffset;
1547
uint8_t *dataPtr = push_->Allocate(dataSize, 4, &vulkanVbuf, &vbBindOffset);
1548
_assert_(dataPtr != nullptr);
1549
memcpy(dataPtr, vdata, dataSize);
1550
1551
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
1552
1553
BindCurrentPipeline();
1554
ApplyDynamicState();
1555
int descSetIndex;
1556
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
1557
BindDescriptors(vulkanUBObuf, descriptors);
1558
renderManager_.Draw(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount);
1559
}
1560
1561
void VKContext::DrawIndexedUP(const void *vdata, int vertexCount, const void *idata, int indexCount) {
1562
_dbg_assert_(vertexCount >= 0);
1563
_dbg_assert_(indexCount >= 0);
1564
if (vertexCount <= 0 || indexCount <= 0) {
1565
return;
1566
}
1567
1568
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
1569
size_t vdataSize = vertexCount * curPipeline_->stride;
1570
uint32_t vbBindOffset;
1571
uint8_t *vdataPtr = push_->Allocate(vdataSize, 4, &vulkanVbuf, &vbBindOffset);
1572
_assert_(vdataPtr != nullptr);
1573
memcpy(vdataPtr, vdata, vdataSize);
1574
1575
size_t idataSize = indexCount * sizeof(u16);
1576
uint32_t ibBindOffset;
1577
uint8_t *idataPtr = push_->Allocate(idataSize, 4, &vulkanIbuf, &ibBindOffset);
1578
_assert_(idataPtr != nullptr);
1579
memcpy(idataPtr, vdata, idataSize);
1580
1581
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
1582
1583
BindCurrentPipeline();
1584
ApplyDynamicState();
1585
int descSetIndex;
1586
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
1587
BindDescriptors(vulkanUBObuf, descriptors);
1588
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, indexCount, 1);
1589
}
1590
1591
void VKContext::DrawIndexedClippedBatchUP(const void *vdata, int vertexCount, const void *idata, int indexCount, Slice<ClippedDraw> draws, const void *ub, size_t ubSize) {
1592
_dbg_assert_(vertexCount >= 0);
1593
_dbg_assert_(indexCount >= 0);
1594
if (vertexCount <= 0 || indexCount <= 0 || draws.is_empty()) {
1595
return;
1596
}
1597
1598
curPipeline_ = (VKPipeline *)draws[0].pipeline;
1599
1600
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
1601
size_t vdataSize = vertexCount * curPipeline_->stride;
1602
uint32_t vbBindOffset;
1603
uint8_t *vdataPtr = push_->Allocate(vdataSize, 4, &vulkanVbuf, &vbBindOffset);
1604
_assert_(vdataPtr != nullptr);
1605
memcpy(vdataPtr, vdata, vdataSize);
1606
1607
constexpr int indexSize = sizeof(u16);
1608
1609
size_t idataSize = indexCount * indexSize;
1610
uint32_t ibBindOffset;
1611
uint8_t *idataPtr = push_->Allocate(idataSize, 4, &vulkanIbuf, &ibBindOffset);
1612
_assert_(idataPtr != nullptr);
1613
memcpy(idataPtr, idata, idataSize);
1614
1615
curPipeline_->SetDynamicUniformData(ub, ubSize);
1616
1617
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
1618
1619
BindCurrentPipeline();
1620
ApplyDynamicState();
1621
1622
for (auto &draw : draws) {
1623
if (draw.pipeline != curPipeline_) {
1624
VKPipeline *vkPipe = (VKPipeline *)draw.pipeline;
1625
renderManager_.BindPipeline(vkPipe->pipeline, vkPipe->flags, pipelineLayout_);
1626
curPipeline_ = (VKPipeline *)draw.pipeline;
1627
curPipeline_->SetDynamicUniformData(ub, ubSize);
1628
}
1629
// TODO: Dirty-check these.
1630
if (draw.bindTexture) {
1631
BindTexture(0, draw.bindTexture);
1632
} else if (draw.bindFramebufferAsTex) {
1633
BindFramebufferAsTexture(draw.bindFramebufferAsTex, 0, draw.aspect, 0);
1634
} else if (draw.bindNativeTexture) {
1635
BindNativeTexture(0, draw.bindNativeTexture);
1636
}
1637
Draw::SamplerState *sstate = draw.samplerState;
1638
BindSamplerStates(0, 1, &sstate);
1639
int descSetIndex;
1640
PackedDescriptor *descriptors = renderManager_.PushDescriptorSet(4, &descSetIndex);
1641
BindDescriptors(vulkanUBObuf, descriptors);
1642
renderManager_.SetScissor(draw.clipx, draw.clipy, draw.clipw, draw.cliph);
1643
renderManager_.DrawIndexed(descSetIndex, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf,
1644
(int)ibBindOffset + draw.indexOffset * indexSize, draw.indexCount, 1);
1645
}
1646
}
1647
1648
void VKContext::BindCurrentPipeline() {
1649
renderManager_.BindPipeline(curPipeline_->pipeline, curPipeline_->flags, pipelineLayout_);
1650
}
1651
1652
void VKContext::Clear(Aspect aspects, uint32_t colorval, float depthVal, int stencilVal) {
1653
int mask = 0;
1654
if (aspects & Aspect::COLOR_BIT)
1655
mask |= VK_IMAGE_ASPECT_COLOR_BIT;
1656
if (aspects & Aspect::DEPTH_BIT)
1657
mask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1658
if (aspects & Aspect::STENCIL_BIT)
1659
mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1660
renderManager_.Clear(colorval, depthVal, stencilVal, mask);
1661
}
1662
1663
DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan, bool useRenderThread) {
1664
return new VKContext(vulkan, useRenderThread);
1665
}
1666
1667
void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 available, VkBool32 enabled) {
1668
char buf[512];
1669
snprintf(buf, sizeof(buf), "%s: Available: %d Enabled: %d", name, (int)available, (int)enabled);
1670
features.push_back(buf);
1671
}
1672
1673
std::vector<std::string> VKContext::GetFeatureList() const {
1674
const VkPhysicalDeviceFeatures &available = vulkan_->GetDeviceFeatures().available.standard;
1675
const VkPhysicalDeviceFeatures &enabled = vulkan_->GetDeviceFeatures().enabled.standard;
1676
1677
std::vector<std::string> features;
1678
AddFeature(features, "dualSrcBlend", available.dualSrcBlend, enabled.dualSrcBlend);
1679
AddFeature(features, "logicOp", available.logicOp, enabled.logicOp);
1680
AddFeature(features, "geometryShader", available.geometryShader, enabled.geometryShader);
1681
AddFeature(features, "depthBounds", available.depthBounds, enabled.depthBounds);
1682
AddFeature(features, "depthClamp", available.depthClamp, enabled.depthClamp);
1683
AddFeature(features, "pipelineStatisticsQuery", available.pipelineStatisticsQuery, enabled.pipelineStatisticsQuery);
1684
AddFeature(features, "samplerAnisotropy", available.samplerAnisotropy, enabled.samplerAnisotropy);
1685
AddFeature(features, "textureCompressionBC", available.textureCompressionBC, enabled.textureCompressionBC);
1686
AddFeature(features, "textureCompressionETC2", available.textureCompressionETC2, enabled.textureCompressionETC2);
1687
AddFeature(features, "textureCompressionASTC_LDR", available.textureCompressionASTC_LDR, enabled.textureCompressionASTC_LDR);
1688
AddFeature(features, "shaderClipDistance", available.shaderClipDistance, enabled.shaderClipDistance);
1689
AddFeature(features, "shaderCullDistance", available.shaderCullDistance, enabled.shaderCullDistance);
1690
AddFeature(features, "occlusionQueryPrecise", available.occlusionQueryPrecise, enabled.occlusionQueryPrecise);
1691
AddFeature(features, "multiDrawIndirect", available.multiDrawIndirect, enabled.multiDrawIndirect);
1692
AddFeature(features, "robustBufferAccess", available.robustBufferAccess, enabled.robustBufferAccess);
1693
AddFeature(features, "fullDrawIndexUint32", available.fullDrawIndexUint32, enabled.fullDrawIndexUint32);
1694
AddFeature(features, "fragmentStoresAndAtomics", available.fragmentStoresAndAtomics, enabled.fragmentStoresAndAtomics);
1695
AddFeature(features, "shaderInt16", available.shaderInt16, enabled.shaderInt16);
1696
1697
AddFeature(features, "multiview", vulkan_->GetDeviceFeatures().available.multiview.multiview, vulkan_->GetDeviceFeatures().enabled.multiview.multiview);
1698
AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader);
1699
AddFeature(features, "presentId", vulkan_->GetDeviceFeatures().available.presentId.presentId, vulkan_->GetDeviceFeatures().enabled.presentId.presentId);
1700
AddFeature(features, "presentWait", vulkan_->GetDeviceFeatures().available.presentWait.presentWait, vulkan_->GetDeviceFeatures().enabled.presentWait.presentWait);
1701
AddFeature(features, "provokingVertexLast", vulkan_->GetDeviceFeatures().available.provokingVertex.provokingVertexLast, vulkan_->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast);
1702
1703
features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat));
1704
1705
return features;
1706
}
1707
1708
std::vector<std::string> VKContext::GetExtensionList(bool device, bool enabledOnly) const {
1709
std::vector<std::string> extensions;
1710
if (enabledOnly) {
1711
const auto& enabled = (device ? vulkan_->GetDeviceExtensionsEnabled() : vulkan_->GetInstanceExtensionsEnabled());
1712
extensions.reserve(enabled.size());
1713
for (auto &iter : enabled) {
1714
extensions.push_back(iter);
1715
}
1716
} else {
1717
const auto& available = (device ? vulkan_->GetDeviceExtensionsAvailable() : vulkan_->GetInstanceExtensionsAvailable());
1718
extensions.reserve(available.size());
1719
for (auto &iter : available) {
1720
extensions.push_back(iter.extensionName);
1721
}
1722
}
1723
return extensions;
1724
}
1725
1726
uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const {
1727
VkFormat vulkan_format = DataFormatToVulkan(fmt);
1728
VkFormatProperties properties;
1729
vkGetPhysicalDeviceFormatProperties(vulkan_->GetCurrentPhysicalDevice(), vulkan_format, &properties);
1730
uint32_t flags = 0;
1731
if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
1732
flags |= FMT_RENDERTARGET;
1733
}
1734
if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1735
flags |= FMT_DEPTHSTENCIL;
1736
}
1737
if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) {
1738
flags |= FMT_TEXTURE;
1739
}
1740
if (properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) {
1741
flags |= FMT_INPUTLAYOUT;
1742
}
1743
if ((properties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT) && (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) {
1744
flags |= FMT_BLIT;
1745
}
1746
if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) {
1747
flags |= FMT_STORAGE_IMAGE;
1748
}
1749
return flags;
1750
}
1751
1752
// A VKFramebuffer is a VkFramebuffer (note caps difference) plus all the textures it owns.
1753
// It also has a reference to the command buffer that it was last rendered to with.
1754
// If it needs to be transitioned, and the frame number matches, use it, otherwise
1755
// use this frame's init command buffer.
1756
class VKFramebuffer : public Framebuffer {
1757
public:
1758
VKFramebuffer(VKRFramebuffer *fb, int multiSampleLevel) : buf_(fb) {
1759
_assert_msg_(fb, "Null fb in VKFramebuffer constructor");
1760
width_ = fb->width;
1761
height_ = fb->height;
1762
layers_ = fb->numLayers;
1763
multiSampleLevel_ = multiSampleLevel;
1764
}
1765
~VKFramebuffer() {
1766
_assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?");
1767
buf_->Vulkan()->Delete().QueueCallback([](VulkanContext *vulkan, void *fb) {
1768
VKRFramebuffer *vfb = static_cast<VKRFramebuffer *>(fb);
1769
delete vfb;
1770
}, buf_);
1771
buf_ = nullptr;
1772
}
1773
VKRFramebuffer *GetFB() const { return buf_; }
1774
void UpdateTag(const char *newTag) override {
1775
buf_->UpdateTag(newTag);
1776
}
1777
const char *Tag() const override {
1778
return buf_->Tag();
1779
}
1780
private:
1781
VKRFramebuffer *buf_;
1782
};
1783
1784
Framebuffer *VKContext::CreateFramebuffer(const FramebufferDesc &desc) {
1785
_assert_(desc.multiSampleLevel >= 0);
1786
_assert_(desc.numLayers > 0);
1787
_assert_(desc.width > 0);
1788
_assert_(desc.height > 0);
1789
1790
VKRFramebuffer *vkrfb = new VKRFramebuffer(vulkan_, &renderManager_.PostInitBarrier(), desc.width, desc.height, desc.numLayers, desc.multiSampleLevel, desc.z_stencil, desc.tag);
1791
return new VKFramebuffer(vkrfb, desc.multiSampleLevel);
1792
}
1793
1794
void VKContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, Aspect aspects, const char *tag) {
1795
VKFramebuffer *src = (VKFramebuffer *)srcfb;
1796
VKFramebuffer *dst = (VKFramebuffer *)dstfb;
1797
1798
int aspectMask = 0;
1799
if (aspects & Aspect::COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
1800
if (aspects & Aspect::DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1801
if (aspects & Aspect::STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1802
1803
renderManager_.CopyFramebuffer(src->GetFB(), VkRect2D{ {x, y}, {(uint32_t)width, (uint32_t)height } }, dst->GetFB(), VkOffset2D{ dstX, dstY }, aspectMask, tag);
1804
}
1805
1806
bool VKContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter filter, const char *tag) {
1807
VKFramebuffer *src = (VKFramebuffer *)srcfb;
1808
VKFramebuffer *dst = (VKFramebuffer *)dstfb;
1809
1810
int aspectMask = 0;
1811
if (aspects & Aspect::COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
1812
if (aspects & Aspect::DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1813
if (aspects & Aspect::STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1814
1815
renderManager_.BlitFramebuffer(src->GetFB(), VkRect2D{ {srcX1, srcY1}, {(uint32_t)(srcX2 - srcX1), (uint32_t)(srcY2 - srcY1) } }, dst->GetFB(), VkRect2D{ {dstX1, dstY1}, {(uint32_t)(dstX2 - dstX1), (uint32_t)(dstY2 - dstY1) } }, aspectMask, filter == FB_BLIT_LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST, tag);
1816
return true;
1817
}
1818
1819
bool VKContext::CopyFramebufferToMemory(Framebuffer *srcfb, Aspect aspects, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) {
1820
VKFramebuffer *src = (VKFramebuffer *)srcfb;
1821
1822
int aspectMask = 0;
1823
if (aspects & Aspect::COLOR_BIT) aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT;
1824
if (aspects & Aspect::DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
1825
if (aspects & Aspect::STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
1826
1827
return renderManager_.CopyFramebufferToMemory(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride, mode, tag);
1828
}
1829
1830
DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) {
1831
if (src) {
1832
return DrawContext::PreferredFramebufferReadbackFormat(src);
1833
}
1834
1835
if (vulkan_->GetSwapchainFormat() == VK_FORMAT_B8G8R8A8_UNORM) {
1836
return Draw::DataFormat::B8G8R8A8_UNORM;
1837
}
1838
return DrawContext::PreferredFramebufferReadbackFormat(src);
1839
}
1840
1841
void VKContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {
1842
VKFramebuffer *fb = (VKFramebuffer *)fbo;
1843
VKRRenderPassLoadAction color = (VKRRenderPassLoadAction)rp.color;
1844
VKRRenderPassLoadAction depth = (VKRRenderPassLoadAction)rp.depth;
1845
VKRRenderPassLoadAction stencil = (VKRRenderPassLoadAction)rp.stencil;
1846
1847
renderManager_.BindFramebufferAsRenderTarget(fb ? fb->GetFB() : nullptr, color, depth, stencil, rp.clearColor, rp.clearDepth, rp.clearStencil, tag);
1848
curFramebuffer_ = fb;
1849
}
1850
1851
void VKContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, Aspect channelBit, int layer) {
1852
VKFramebuffer *fb = (VKFramebuffer *)fbo;
1853
_assert_(binding >= 0 && binding < MAX_BOUND_TEXTURES);
1854
1855
// TODO: There are cases where this is okay, actually. But requires layout transitions and stuff -
1856
// we're not ready for this.
1857
_assert_(fb != curFramebuffer_);
1858
1859
int aspect = 0;
1860
switch (channelBit) {
1861
case Aspect::COLOR_BIT:
1862
aspect = VK_IMAGE_ASPECT_COLOR_BIT;
1863
break;
1864
case Aspect::DEPTH_BIT:
1865
aspect = VK_IMAGE_ASPECT_DEPTH_BIT;
1866
break;
1867
default:
1868
// Hm, can we texture from stencil?
1869
_assert_(false);
1870
break;
1871
}
1872
1873
boundTextures_[binding].reset(nullptr);
1874
boundImageView_[binding] = renderManager_.BindFramebufferAsTexture(fb->GetFB(), binding, aspect, layer);
1875
}
1876
1877
void VKContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {
1878
VKFramebuffer *fb = (VKFramebuffer *)fbo;
1879
if (fb) {
1880
*w = fb->GetFB()->width;
1881
*h = fb->GetFB()->height;
1882
} else {
1883
*w = vulkan_->GetBackbufferWidth();
1884
*h = vulkan_->GetBackbufferHeight();
1885
}
1886
}
1887
1888
void VKContext::HandleEvent(Event ev, int width, int height, void *param1, void *param2) {
1889
switch (ev) {
1890
case Event::LOST_BACKBUFFER:
1891
renderManager_.DestroyBackbuffers();
1892
break;
1893
case Event::GOT_BACKBUFFER:
1894
renderManager_.CreateBackbuffers();
1895
break;
1896
default:
1897
_assert_(false);
1898
break;
1899
}
1900
}
1901
1902
void VKContext::InvalidateFramebuffer(FBInvalidationStage stage, Aspect aspects) {
1903
VkImageAspectFlags flags = 0;
1904
if (aspects & Aspect::COLOR_BIT)
1905
flags |= VK_IMAGE_ASPECT_COLOR_BIT;
1906
if (aspects & Aspect::DEPTH_BIT)
1907
flags |= VK_IMAGE_ASPECT_DEPTH_BIT;
1908
if (aspects & Aspect::STENCIL_BIT)
1909
flags |= VK_IMAGE_ASPECT_STENCIL_BIT;
1910
if (stage == FB_INVALIDATION_LOAD) {
1911
renderManager_.SetLoadDontCare(flags);
1912
} else if (stage == FB_INVALIDATION_STORE) {
1913
renderManager_.SetStoreDontCare(flags);
1914
}
1915
}
1916
1917
uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) {
1918
switch (obj) {
1919
case NativeObject::CONTEXT:
1920
return (uint64_t)vulkan_;
1921
case NativeObject::INIT_COMMANDBUFFER:
1922
return (uint64_t)renderManager_.GetInitCmd();
1923
case NativeObject::BOUND_TEXTURE0_IMAGEVIEW:
1924
return (uint64_t)boundImageView_[0];
1925
case NativeObject::BOUND_TEXTURE1_IMAGEVIEW:
1926
return (uint64_t)boundImageView_[1];
1927
case NativeObject::RENDER_MANAGER:
1928
return (uint64_t)(uintptr_t)&renderManager_;
1929
case NativeObject::NULL_IMAGEVIEW:
1930
return (uint64_t)GetNullTexture()->GetImageView();
1931
case NativeObject::NULL_IMAGEVIEW_ARRAY:
1932
return (uint64_t)GetNullTexture()->GetImageArrayView();
1933
case NativeObject::TEXTURE_VIEW:
1934
return (uint64_t)(((VKTexture *)srcObject)->GetImageView());
1935
case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_ALL_LAYERS:
1936
return (uint64_t)curFramebuffer_->GetFB()->color.texAllLayersView;
1937
case NativeObject::BOUND_FRAMEBUFFER_COLOR_IMAGEVIEW_RT:
1938
return (uint64_t)curFramebuffer_->GetFB()->GetRTView();
1939
case NativeObject::THIN3D_PIPELINE_LAYOUT:
1940
return (uint64_t)pipelineLayout_;
1941
case NativeObject::PUSH_POOL:
1942
return (uint64_t)push_;
1943
default:
1944
Crash();
1945
return 0;
1946
}
1947
}
1948
1949
void VKContext::DebugAnnotate(const char *annotation) {
1950
renderManager_.DebugAnnotate(annotation);
1951
}
1952
1953
} // namespace Draw
1954
1955