~ppsspp/ppsspp/ppsspp_1.3.0

« back to all changes in this revision

Viewing changes to ext/native/thin3d/thin3d_vulkan.cpp

  • Committer: Sérgio Benjamim
  • Date: 2017-01-02 00:12:05 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20170102001205-cxbta9za203nmjwm
1.3.0 source (from ppsspp_1.3.0-r160.p5.l1762.a165.t83~56~ubuntu16.04.1.tar.xz).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <stdio.h>
 
19
#include <vector>
 
20
#include <string>
 
21
#include <map>
 
22
#include <assert.h>
 
23
 
 
24
#include "Common/Vulkan/SPIRVDisasm.h"
 
25
 
 
26
#include "base/logging.h"
 
27
#include "base/display.h"
 
28
#include "base/stringutil.h"
 
29
#include "image/zim_load.h"
 
30
#include "math/lin/matrix4x4.h"
 
31
#include "math/dataconv.h"
 
32
#include "thin3d/thin3d.h"
 
33
 
 
34
#include "Common/Vulkan/VulkanContext.h"
 
35
#include "Common/Vulkan/VulkanImage.h"
 
36
#include "Common/Vulkan/VulkanMemory.h"
 
37
 
 
38
// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point.
 
39
// binding 0 - uniform data
 
40
// binding 1 - sampler
 
41
//
 
42
// Vertex data lives in a separate namespace (location = 0, 1, etc)
 
43
 
 
44
#include "Common/Vulkan/VulkanLoader.h"
 
45
 
 
46
// This can actually be replaced with a cast as the values are in the right order.
 
47
static const VkCompareOp compToVK[] = {
 
48
        VK_COMPARE_OP_NEVER,
 
49
        VK_COMPARE_OP_LESS,
 
50
        VK_COMPARE_OP_EQUAL,
 
51
        VK_COMPARE_OP_LESS_OR_EQUAL,
 
52
        VK_COMPARE_OP_GREATER,
 
53
        VK_COMPARE_OP_NOT_EQUAL,
 
54
        VK_COMPARE_OP_GREATER_OR_EQUAL,
 
55
        VK_COMPARE_OP_ALWAYS
 
56
};
 
57
 
 
58
// So can this.
 
59
static const VkBlendOp blendEqToGL[] = {
 
60
        VK_BLEND_OP_ADD,
 
61
        VK_BLEND_OP_SUBTRACT,
 
62
        VK_BLEND_OP_REVERSE_SUBTRACT,
 
63
};
 
64
 
 
65
static const VkBlendFactor blendFactorToVk[] = {
 
66
        VK_BLEND_FACTOR_ZERO,
 
67
        VK_BLEND_FACTOR_ONE,
 
68
        VK_BLEND_FACTOR_SRC_COLOR,
 
69
        VK_BLEND_FACTOR_SRC_ALPHA,
 
70
        VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
 
71
        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
 
72
        VK_BLEND_FACTOR_DST_COLOR,
 
73
        VK_BLEND_FACTOR_DST_ALPHA,
 
74
        VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
 
75
        VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
 
76
        VK_BLEND_FACTOR_CONSTANT_COLOR,
 
77
};
 
78
 
 
79
static const VkLogicOp logicOpToVK[] = {
 
80
        VK_LOGIC_OP_CLEAR,
 
81
        VK_LOGIC_OP_SET,
 
82
        VK_LOGIC_OP_COPY,
 
83
        VK_LOGIC_OP_COPY_INVERTED,
 
84
        VK_LOGIC_OP_NO_OP,
 
85
        VK_LOGIC_OP_INVERT,
 
86
        VK_LOGIC_OP_AND,
 
87
        VK_LOGIC_OP_NAND,
 
88
        VK_LOGIC_OP_OR,
 
89
        VK_LOGIC_OP_NOR,
 
90
        VK_LOGIC_OP_XOR,
 
91
        VK_LOGIC_OP_EQUIVALENT,
 
92
        VK_LOGIC_OP_AND_REVERSE,
 
93
        VK_LOGIC_OP_AND_INVERTED,
 
94
        VK_LOGIC_OP_OR_REVERSE,
 
95
        VK_LOGIC_OP_OR_INVERTED,
 
96
};
 
97
 
 
98
static const VkPrimitiveTopology primToVK[] = {
 
99
        VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
 
100
        VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
 
101
        VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
 
102
};
 
103
 
 
104
static inline void Uint8x4ToFloat4(uint32_t u, float f[4]) {
 
105
        f[0] = ((u >> 0) & 0xFF) * (1.0f / 255.0f);
 
106
        f[1] = ((u >> 8) & 0xFF) * (1.0f / 255.0f);
 
107
        f[2] = ((u >> 16) & 0xFF) * (1.0f / 255.0f);
 
108
        f[3] = ((u >> 24) & 0xFF) * (1.0f / 255.0f);
 
109
}
 
110
 
 
111
 
 
112
class Thin3DVKBlendState : public Thin3DBlendState {
 
113
public:
 
114
        bool blendEnabled;
 
115
        VkBlendOp eqCol, eqAlpha;
 
116
        VkBlendFactor srcCol, srcAlpha, dstColor, dstAlpha;
 
117
        bool logicEnabled;
 
118
        VkLogicOp logicOp;
 
119
 
 
120
        void ToVulkan(VkPipelineColorBlendStateCreateInfo *info, VkPipelineColorBlendAttachmentState *attachments) {
 
121
                memset(info, 0, sizeof(*info));
 
122
                info->sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
 
123
                info->attachmentCount = 1;
 
124
                info->logicOp = logicOp;
 
125
                info->logicOpEnable = logicEnabled;
 
126
                attachments[0].blendEnable = blendEnabled;
 
127
                attachments[0].colorBlendOp = eqCol;
 
128
                attachments[0].alphaBlendOp = eqAlpha;
 
129
                attachments[0].colorWriteMask = 0xF;
 
130
                attachments[0].dstAlphaBlendFactor = dstAlpha;
 
131
                attachments[0].dstColorBlendFactor = dstColor;
 
132
                attachments[0].srcAlphaBlendFactor = srcAlpha;
 
133
                attachments[0].srcColorBlendFactor = srcCol;
 
134
                info->pAttachments = attachments;
 
135
        }
 
136
};
 
137
 
 
138
class Thin3DVKDepthStencilState : public Thin3DDepthStencilState {
 
139
public:
 
140
        bool depthTestEnabled;
 
141
        bool depthWriteEnabled;
 
142
        VkCompareOp depthComp;
 
143
 
 
144
        void ToVulkan(VkPipelineDepthStencilStateCreateInfo *info) {
 
145
                memset(info, 0, sizeof(*info));
 
146
                info->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
 
147
                info->depthCompareOp = depthComp;
 
148
                info->depthTestEnable = depthTestEnabled;
 
149
                info->depthWriteEnable = depthWriteEnabled;
 
150
                info->stencilTestEnable = false;
 
151
                info->depthBoundsTestEnable = false;
 
152
        }
 
153
};
 
154
 
 
155
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
 
156
// to avoid synchronization issues.
 
157
class Thin3DVKBuffer : public Thin3DBuffer {
 
158
public:
 
159
        Thin3DVKBuffer(size_t size, uint32_t flags) : dataSize_(size) {
 
160
                data_ = new uint8_t[size];
 
161
        }
 
162
        ~Thin3DVKBuffer() override {
 
163
                delete[] data_;
 
164
        }
 
165
 
 
166
        void SetData(const uint8_t *data, size_t size) override {
 
167
                delete[] data_;
 
168
                dataSize_ = size;
 
169
                data_ = new uint8_t[size];
 
170
                if (data) {
 
171
                        memcpy(data_, data, size);
 
172
                }
 
173
        }
 
174
 
 
175
        void SubData(const uint8_t *data, size_t offset, size_t size) override {
 
176
                memcpy(data_, data_ + offset, size);
 
177
        }
 
178
 
 
179
        size_t GetSize() const { return dataSize_; }
 
180
        const uint8_t *GetData() const { return data_; }
 
181
 
 
182
private:
 
183
        uint8_t *data_;
 
184
        size_t dataSize_;
 
185
};
 
186
 
 
187
// Not registering this as a resource holder, instead ShaderSet is registered. It will
 
188
// invoke Compile again to recreate the shader then link them together.
 
189
class Thin3DVKShader : public Thin3DShader {
 
190
public:
 
191
        Thin3DVKShader(bool isFragmentShader) : module_(VK_NULL_HANDLE), ok_(false) {
 
192
                stage_ = isFragmentShader ? VK_SHADER_STAGE_FRAGMENT_BIT : VK_SHADER_STAGE_VERTEX_BIT;
 
193
        }
 
194
        bool Compile(VulkanContext *vulkan, const char *source);
 
195
        const std::string &GetSource() const { return source_; }
 
196
        ~Thin3DVKShader() {
 
197
                if (module_) {
 
198
                        vkDestroyShaderModule(device_, module_, nullptr);
 
199
                }
 
200
        }
 
201
        VkShaderModule Get() const { return module_; }
 
202
 
 
203
private:
 
204
        VkDevice device_;
 
205
        VkShaderModule module_;
 
206
        VkShaderStageFlagBits stage_;
 
207
        bool ok_;
 
208
        std::string source_;  // So we can recompile in case of context loss.
 
209
};
 
210
 
 
211
bool Thin3DVKShader::Compile(VulkanContext *vulkan, const char *source) {
 
212
        // We'll need this to free it later.
 
213
        device_ = vulkan->GetDevice();
 
214
        this->source_ = source;
 
215
        std::vector<uint32_t> spirv;
 
216
        if (!GLSLtoSPV(stage_, source, spirv)) {
 
217
                return false;
 
218
        }
 
219
 
 
220
        // Just for kicks, sanity check the SPIR-V. The disasm isn't perfect
 
221
        // but gives you some idea of what's going on.
 
222
#if 0
 
223
        std::string disasm;
 
224
        if (DisassembleSPIRV(spirv, &disasm)) {
 
225
                OutputDebugStringA(disasm.c_str());
 
226
        }
 
227
#endif
 
228
 
 
229
        if (vulkan->CreateShaderModule(spirv, &module_)) {
 
230
                ok_ = true;
 
231
        } else {
 
232
                ok_ = false;
 
233
        }
 
234
 
 
235
        return ok_;
 
236
}
 
237
 
 
238
 
 
239
inline VkFormat ConvertVertexDataTypeToVk(T3DVertexDataType type) {
 
240
        switch (type) {
 
241
        case FLOATx2: return VK_FORMAT_R32G32_SFLOAT;
 
242
        case FLOATx3: return VK_FORMAT_R32G32B32_SFLOAT;
 
243
        case FLOATx4: return VK_FORMAT_R32G32B32A32_SFLOAT;
 
244
        case UNORM8x4: return VK_FORMAT_R8G8B8A8_UNORM;
 
245
        default: return VK_FORMAT_UNDEFINED;
 
246
        }
 
247
}
 
248
 
 
249
class Thin3DVKVertexFormat : public Thin3DVertexFormat {
 
250
public:
 
251
        void ToVulkan(VkPipelineVertexInputStateCreateInfo *info, VkVertexInputAttributeDescription *attrDescs, VkVertexInputBindingDescription *bindDescs) {
 
252
                memset(info, 0, sizeof(*info));
 
253
                info->sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
 
254
                for (uint32_t i = 0; i < components_.size(); i++) {
 
255
                        attrDescs[i].binding = 0;
 
256
                        attrDescs[i].format = ConvertVertexDataTypeToVk(components_[i].type);
 
257
                        attrDescs[i].location = (int)components_[i].semantic;
 
258
                        attrDescs[i].offset = components_[i].offset;
 
259
                }
 
260
                bindDescs[0].binding = 0;
 
261
                bindDescs[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
 
262
                bindDescs[0].stride = stride_;
 
263
 
 
264
                info->vertexAttributeDescriptionCount = (uint32_t)components_.size();
 
265
                info->pVertexAttributeDescriptions = attrDescs;
 
266
                info->vertexBindingDescriptionCount = 1;
 
267
                info->pVertexBindingDescriptions = bindDescs;
 
268
                info->flags = 0;
 
269
        }
 
270
 
 
271
        bool RequiresBuffer() {
 
272
                return false;
 
273
        }
 
274
 
 
275
        std::vector<Thin3DVertexComponent> components_;
 
276
        int stride_;
 
277
};
 
278
 
 
279
class Thin3DVKShaderSet : public Thin3DShaderSet {
 
280
public:
 
281
        Thin3DVKShaderSet() {
 
282
                // HACK! Hardcoded
 
283
                uboSize_ = 16 * sizeof(float);  // WorldViewProj
 
284
                ubo_ = new uint8_t[uboSize_];
 
285
        }
 
286
        ~Thin3DVKShaderSet() {
 
287
                vshader->Release();
 
288
                fshader->Release();
 
289
                delete[] ubo_;
 
290
        }
 
291
        bool Link();
 
292
 
 
293
        // Returns the binding offset, and the VkBuffer to bind.
 
294
        size_t PushUBO(VulkanPushBuffer *buf, VulkanContext *vulkan, VkBuffer *vkbuf) {
 
295
                return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment, vkbuf);
 
296
        }
 
297
 
 
298
        int GetUniformLoc(const char *name);
 
299
 
 
300
        void SetVector(const char *name, float *value, int n) override;
 
301
        void SetMatrix4x4(const char *name, const float value[16]) override;
 
302
 
 
303
        int GetUBOSize() const {
 
304
                return uboSize_;
 
305
        }
 
306
 
 
307
        Thin3DVKShader *vshader;
 
308
        Thin3DVKShader *fshader;
 
309
 
 
310
private:
 
311
        uint8_t *ubo_;
 
312
        int uboSize_;
 
313
};
 
314
 
 
315
struct PipelineKey {
 
316
        Thin3DVKDepthStencilState *depthStencil;
 
317
        Thin3DVKBlendState *blend;
 
318
        Thin3DVKShaderSet *shaderSet;
 
319
        VkPrimitiveTopology topology;
 
320
        T3DCullMode cullMode;
 
321
 
 
322
        // etc etc
 
323
 
 
324
        bool operator < (const PipelineKey &other) const {
 
325
                if (depthStencil < other.depthStencil) return true; else if (depthStencil > other.depthStencil) return false;
 
326
                if (blend < other.blend) return true; else if (blend > other.blend) return false;
 
327
                if (shaderSet < other.shaderSet) return true; else if (shaderSet > other.shaderSet) return false;
 
328
                if (topology < other.topology) return true; else if (topology > other.topology) return false;
 
329
                if (cullMode < other.cullMode) return true; else if (cullMode > other.cullMode) return false;
 
330
                // etc etc
 
331
                return false;
 
332
        }
 
333
};
 
334
 
 
335
 
 
336
 
 
337
class Thin3DVKTexture;
 
338
class Thin3DVKSamplerState;
 
339
 
 
340
struct DescriptorSetKey {
 
341
        Thin3DVKTexture *texture_;
 
342
        Thin3DVKSamplerState *sampler_;
 
343
        VkBuffer buffer_;
 
344
 
 
345
        bool operator < (const DescriptorSetKey &other) const {
 
346
                if (texture_ < other.texture_) return true; else if (texture_ > other.texture_) return false;
 
347
                if (sampler_ < other.sampler_) return true; else if (sampler_ > other.sampler_) return false;
 
348
                if (buffer_ < other.buffer_) return true; else if (buffer_ > other.buffer_) return false;
 
349
                return false;
 
350
        }
 
351
};
 
352
 
 
353
class Thin3DVKContext : public Thin3DContext {
 
354
public:
 
355
        Thin3DVKContext(VulkanContext *vulkan);
 
356
        virtual ~Thin3DVKContext();
 
357
 
 
358
        Thin3DDepthStencilState *CreateDepthStencilState(bool depthTestEnabled, bool depthWriteEnabled, T3DComparison depthCompare) override;
 
359
        Thin3DBlendState *CreateBlendState(const T3DBlendStateDesc &desc) override;
 
360
        Thin3DBuffer *CreateBuffer(size_t size, uint32_t usageFlags) override;
 
361
        Thin3DShaderSet *CreateShaderSet(Thin3DShader *vshader, Thin3DShader *fshader) override;
 
362
        Thin3DVertexFormat *CreateVertexFormat(const std::vector<Thin3DVertexComponent> &components, int stride, Thin3DShader *vshader) override;
 
363
        Thin3DSamplerState *CreateSamplerState(const T3DSamplerStateDesc &desc) override;
 
364
        Thin3DTexture *CreateTexture(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) override;
 
365
        Thin3DTexture *CreateTexture() override;
 
366
 
 
367
        // Bound state objects
 
368
        void SetBlendState(Thin3DBlendState *state) override {
 
369
                Thin3DVKBlendState *s = static_cast<Thin3DVKBlendState *>(state);
 
370
                curBlendState_ = s;
 
371
        }
 
372
 
 
373
        // Bound state objects
 
374
        void SetDepthStencilState(Thin3DDepthStencilState *state) override {
 
375
                Thin3DVKDepthStencilState *s = static_cast<Thin3DVKDepthStencilState *>(state);
 
376
                curDepthStencilState_ = s;
 
377
        }
 
378
 
 
379
        // The implementation makes the choice of which shader code to use.
 
380
        Thin3DShader *CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) override;
 
381
        Thin3DShader *CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) override;
 
382
 
 
383
        void SetScissorEnabled(bool enable) override {
 
384
                scissorEnabled_ = enable;
 
385
                scissorDirty_ = true;
 
386
        }
 
387
 
 
388
        void SetScissorRect(int left, int top, int width, int height) override;
 
389
 
 
390
        void SetViewports(int count, T3DViewport *viewports) override;
 
391
 
 
392
        void SetTextures(int start, int count, Thin3DTexture **textures) override;
 
393
 
 
394
        void SetSamplerStates(int start, int count, Thin3DSamplerState **state) override;
 
395
 
 
396
        void SetRenderState(T3DRenderState rs, uint32_t value) override;
 
397
 
 
398
        // TODO: Add more sophisticated draws.
 
399
        void Draw(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, Thin3DBuffer *vdata, int vertexCount, int offset) override;
 
400
        void DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, Thin3DBuffer *vdata, Thin3DBuffer *idata, int vertexCount, int offset) override;
 
401
        void DrawUP(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, const void *vdata, int vertexCount) override;
 
402
 
 
403
        void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
 
404
 
 
405
        void Begin(bool clear, uint32_t colorval, float depthVal, int stencilVal) override;
 
406
        void End() override;
 
407
 
 
408
        std::string GetInfoString(T3DInfo info) const override {
 
409
                // TODO: Make these actually query the right information
 
410
                switch (info) {
 
411
                case APINAME: return "Vulkan";
 
412
                case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties().deviceName;
 
413
                case VENDOR: return StringFromFormat("%08x", vulkan_->GetPhysicalDeviceProperties().vendorID);
 
414
                case RENDERER: return StringFromFormat("%08x", vulkan_->GetPhysicalDeviceProperties().driverVersion);
 
415
                case SHADELANGVERSION: return "N/A";;
 
416
                case APIVERSION: 
 
417
                {
 
418
                        uint32_t ver = vulkan_->GetPhysicalDeviceProperties().apiVersion;
 
419
                        return StringFromFormat("%d.%d.%d", ver >> 22, (ver >> 12) & 0x3ff, ver & 0xfff);
 
420
                }
 
421
                default: return "?";
 
422
                }
 
423
        }
 
424
 
 
425
        VkPipeline GetOrCreatePipeline();
 
426
        VkDescriptorSet GetOrCreateDescriptorSet(VkBuffer buffer);
 
427
 
 
428
        std::vector<std::string> GetFeatureList() override;
 
429
 
 
430
private:
 
431
        void ApplyDynamicState();
 
432
        void DirtyDynamicState();
 
433
 
 
434
        VulkanContext *vulkan_;
 
435
 
 
436
        // These are used to compose the pipeline cache key.
 
437
        Thin3DVKBlendState *curBlendState_;
 
438
        Thin3DVKDepthStencilState *curDepthStencilState_;
 
439
        Thin3DVKShaderSet *curShaderSet_;
 
440
        VkPrimitiveTopology curPrim_;
 
441
        Thin3DVKVertexFormat *curVertexFormat_;
 
442
        T3DCullMode curCullMode_;
 
443
 
 
444
        // We keep a pipeline state cache.
 
445
        std::map<PipelineKey, VkPipeline> pipelines_;
 
446
 
 
447
        VkDescriptorSetLayout descriptorSetLayout_;
 
448
        VkPipelineLayout pipelineLayout_;
 
449
        VkPipelineCache pipelineCache_;
 
450
 
 
451
        VkCommandPool cmdPool_;
 
452
        VkDevice device_;
 
453
        VkQueue queue_;
 
454
        int queueFamilyIndex_;
 
455
 
 
456
        // State to apply at the next draw call if viewportDirty or scissorDirty are true.
 
457
        bool viewportDirty_;
 
458
        VkViewport viewport_;
 
459
        bool scissorDirty_;
 
460
        VkRect2D scissor_;
 
461
        bool scissorEnabled_;
 
462
 
 
463
        VkRect2D noScissor_;  // Simply a scissor covering the screen.
 
464
 
 
465
        enum {MAX_BOUND_TEXTURES = 1};
 
466
        Thin3DVKTexture *boundTextures_[MAX_BOUND_TEXTURES];
 
467
        Thin3DVKSamplerState *boundSamplers_[MAX_BOUND_TEXTURES];
 
468
 
 
469
        VkCommandBuffer cmd_; // The current one
 
470
 
 
471
        struct FrameData {
 
472
                VulkanPushBuffer *pushBuffer;
 
473
 
 
474
                // Per-frame descriptor set cache. As it's per frame and reset every frame, we don't need to
 
475
                // worry about invalidating descriptors pointing to deleted textures.
 
476
                std::map<DescriptorSetKey, VkDescriptorSet> descSets_;
 
477
                VkDescriptorPool descriptorPool;
 
478
        };
 
479
 
 
480
        FrameData frame_[2];
 
481
 
 
482
        int frameNum_;
 
483
        VulkanPushBuffer *push_;
 
484
};
 
485
 
 
486
VkFormat FormatToVulkan(T3DImageFormat fmt, int *bpp) {
 
487
        switch (fmt) {
 
488
        case RGBA8888: *bpp = 32; return VK_FORMAT_R8G8B8A8_UNORM;
 
489
        case RGBA4444: *bpp = 16; return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
 
490
        case D24S8: *bpp = 32; return VK_FORMAT_D24_UNORM_S8_UINT;
 
491
        case D16: *bpp = 16; return VK_FORMAT_D16_UNORM;
 
492
        default: return VK_FORMAT_UNDEFINED;
 
493
        }
 
494
}
 
495
 
 
496
class Thin3DVKSamplerState : public Thin3DSamplerState {
 
497
public:
 
498
        Thin3DVKSamplerState(VulkanContext *vulkan, const T3DSamplerStateDesc &desc) : vulkan_(vulkan) {
 
499
                VkSamplerCreateInfo s = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
 
500
                s.addressModeU = desc.wrapS ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
 
501
                s.addressModeV = desc.wrapT ? VK_SAMPLER_ADDRESS_MODE_REPEAT : VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
 
502
                s.magFilter = desc.magFilt == T3DTextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
 
503
                s.minFilter = desc.minFilt == T3DTextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
 
504
                s.mipmapMode = desc.mipFilt == T3DTextureFilter::LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
 
505
                s.maxLod = 0.0;  // TODO: Actually support mipmaps
 
506
 
 
507
                VkResult res = vkCreateSampler(vulkan_->GetDevice(), &s, nullptr, &sampler_);
 
508
                assert(VK_SUCCESS == res);
 
509
        }
 
510
        ~Thin3DVKSamplerState() {
 
511
                vkDestroySampler(vulkan_->GetDevice(), sampler_, nullptr);
 
512
        }
 
513
 
 
514
        VkSampler GetSampler() { return sampler_; }
 
515
 
 
516
private:
 
517
        VulkanContext *vulkan_;
 
518
        VkSampler sampler_;
 
519
};
 
520
 
 
521
Thin3DSamplerState *Thin3DVKContext::CreateSamplerState(const T3DSamplerStateDesc &desc) {
 
522
        return new Thin3DVKSamplerState(vulkan_, desc);
 
523
}
 
524
 
 
525
void Thin3DVKContext::SetSamplerStates(int start, int count, Thin3DSamplerState **state) {
 
526
        for (int i = start; i < start + count; i++) {
 
527
                boundSamplers_[i] = (Thin3DVKSamplerState *)state[i];
 
528
        }
 
529
}
 
530
 
 
531
enum class TextureState {
 
532
        UNINITIALIZED,
 
533
        STAGED,
 
534
        INITIALIZED,
 
535
        PENDING_DESTRUCTION,
 
536
};
 
537
 
 
538
class Thin3DVKTexture : public Thin3DTexture {
 
539
public:
 
540
        Thin3DVKTexture(VulkanContext *vulkan) : vulkan_(vulkan), vkTex_(nullptr) {
 
541
        }
 
542
 
 
543
        Thin3DVKTexture(VulkanContext *vulkan, T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels)
 
544
                : vulkan_(vulkan), format_(format), mipLevels_(mipLevels) {
 
545
                Create(type, format, width, height, depth, mipLevels);
 
546
        }
 
547
 
 
548
        ~Thin3DVKTexture() {
 
549
                Destroy();
 
550
        }
 
551
 
 
552
        bool Create(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) override {
 
553
                format_ = format;
 
554
                mipLevels_ = mipLevels;
 
555
                width_ = width;
 
556
                height_ = height;
 
557
                depth_ = depth;
 
558
                vkTex_ = new VulkanTexture(vulkan_);
 
559
                // We don't actually do anything here.
 
560
                return true;
 
561
        }
 
562
 
 
563
        void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
 
564
        void Finalize(int zim_flags) override;
 
565
        void AutoGenMipmaps() override {}
 
566
 
 
567
        VkImageView GetImageView() { return vkTex_->GetImageView(); }
 
568
 
 
569
private:
 
570
        void Destroy() {
 
571
                if (vkTex_) {
 
572
                        vkTex_->Destroy();
 
573
                        delete vkTex_;
 
574
                }
 
575
        }
 
576
 
 
577
        VulkanContext *vulkan_;
 
578
        VulkanTexture *vkTex_;
 
579
 
 
580
        int mipLevels_;
 
581
 
 
582
        T3DImageFormat format_;
 
583
};
 
584
 
 
585
Thin3DVKContext::Thin3DVKContext(VulkanContext *vulkan)
 
586
        : viewportDirty_(false), scissorDirty_(false), vulkan_(vulkan), frameNum_(0) {
 
587
        device_ = vulkan->GetDevice();
 
588
 
 
589
        queue_ = vulkan->GetGraphicsQueue();
 
590
        queueFamilyIndex_ = vulkan->GetGraphicsQueueFamilyIndex();
 
591
        noScissor_.offset.x = 0;
 
592
        noScissor_.offset.y = 0;
 
593
        noScissor_.extent.width = pixel_xres;
 
594
        noScissor_.extent.height = pixel_yres;
 
595
        scissor_ = noScissor_;
 
596
        viewport_.x = 0;
 
597
        viewport_.y = 0;
 
598
        viewport_.width = pixel_xres;
 
599
        viewport_.height = pixel_yres;
 
600
        viewport_.minDepth = 0.0f;
 
601
        viewport_.maxDepth = 0.0f;
 
602
        memset(boundTextures_, 0, sizeof(boundTextures_));
 
603
        CreatePresets();
 
604
 
 
605
        VkCommandPoolCreateInfo p = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
 
606
        p.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
 
607
        p.queueFamilyIndex = vulkan->GetGraphicsQueueFamilyIndex();
 
608
        VkResult res = vkCreateCommandPool(device_, &p, nullptr, &cmdPool_);
 
609
        assert(VK_SUCCESS == res);
 
610
 
 
611
        VkDescriptorPoolSize dpTypes[2];
 
612
        dpTypes[0].descriptorCount = 200;
 
613
        dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
 
614
        dpTypes[1].descriptorCount = 200;
 
615
        dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 
616
 
 
617
        VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
 
618
        dp.flags = 0;   // Don't want to mess around with individually freeing these, let's go dynamic each frame.
 
619
        dp.maxSets = 200;  // 200 textures per frame should be enough for the UI...
 
620
        dp.pPoolSizes = dpTypes;
 
621
        dp.poolSizeCount = ARRAY_SIZE(dpTypes);
 
622
        res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[0].descriptorPool);
 
623
        assert(VK_SUCCESS == res);
 
624
        res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[1].descriptorPool);
 
625
        assert(VK_SUCCESS == res);
 
626
 
 
627
        frame_[0].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024);
 
628
        frame_[1].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024);
 
629
 
 
630
        // binding 0 - uniform data
 
631
        // binding 1 - combined sampler/image
 
632
        VkDescriptorSetLayoutBinding bindings[2];
 
633
        bindings[0].descriptorCount = 1;
 
634
        bindings[0].pImmutableSamplers = nullptr;
 
635
        bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
 
636
        bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
 
637
        bindings[0].binding = 0;
 
638
        bindings[1].descriptorCount = 1;
 
639
        bindings[1].pImmutableSamplers = nullptr;
 
640
        bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 
641
        bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
 
642
        bindings[1].binding = 1;
 
643
 
 
644
        VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
 
645
        dsl.bindingCount = 2;
 
646
        dsl.pBindings = bindings;
 
647
        res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_);
 
648
        assert(VK_SUCCESS == res);
 
649
 
 
650
        VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
 
651
        pl.pPushConstantRanges = nullptr;
 
652
        pl.pushConstantRangeCount = 0;
 
653
        pl.setLayoutCount = 1;
 
654
        pl.pSetLayouts = &descriptorSetLayout_;
 
655
        res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_);
 
656
        assert(VK_SUCCESS == res);
 
657
 
 
658
        pipelineCache_ = vulkan_->CreatePipelineCache();
 
659
}
 
660
 
 
661
Thin3DVKContext::~Thin3DVKContext() {
 
662
        for (auto x : pipelines_) {
 
663
                vkDestroyPipeline(device_, x.second, nullptr);
 
664
        }
 
665
        vkDestroyCommandPool(device_, cmdPool_, nullptr);
 
666
        // This also destroys all descriptor sets.
 
667
        for (int i = 0; i < 2; i++) {
 
668
                frame_[i].descSets_.clear();
 
669
                vkDestroyDescriptorPool(device_, frame_[i].descriptorPool, nullptr);
 
670
                frame_[i].pushBuffer->Destroy(vulkan_);
 
671
                delete frame_[i].pushBuffer;
 
672
        }
 
673
        vkDestroyDescriptorSetLayout(device_, descriptorSetLayout_, nullptr);
 
674
        vkDestroyPipelineLayout(device_, pipelineLayout_, nullptr);
 
675
        vkDestroyPipelineCache(device_, pipelineCache_, nullptr);
 
676
}
 
677
 
 
678
void Thin3DVKContext::Begin(bool clear, uint32_t colorval, float depthVal, int stencilVal) {
 
679
        VkClearValue clearVal[2] = {};
 
680
        Uint8x4ToFloat4(colorval, clearVal[0].color.float32);
 
681
 
 
682
        // // Debug flicker - used to see if we swap at all. no longer necessary
 
683
        // if (frameNum_ & 1)
 
684
        //      clearVal[0].color.float32[2] = 1.0f;
 
685
 
 
686
        clearVal[1].depthStencil.depth = depthVal;
 
687
        clearVal[1].depthStencil.stencil = stencilVal;
 
688
 
 
689
        cmd_ = vulkan_->BeginSurfaceRenderPass(clearVal);
 
690
 
 
691
        FrameData *frame = &frame_[frameNum_ & 1];
 
692
        push_ = frame->pushBuffer;
 
693
 
 
694
        // OK, we now know that nothing is reading from this frame's data pushbuffer,
 
695
        push_->Reset();
 
696
        push_->Begin(vulkan_);
 
697
 
 
698
        frame->descSets_.clear();
 
699
        VkResult result = vkResetDescriptorPool(device_, frame->descriptorPool, 0);
 
700
        assert(result == VK_SUCCESS);
 
701
 
 
702
        noScissor_.extent.width = pixel_xres;
 
703
        noScissor_.extent.height = pixel_yres;
 
704
        scissorDirty_ = true;
 
705
        viewportDirty_ = true;
 
706
}
 
707
 
 
708
void Thin3DVKContext::End() {
 
709
        // Stop collecting data in the frame's data pushbuffer.
 
710
        push_->End();
 
711
        vulkan_->EndSurfaceRenderPass();
 
712
 
 
713
        frameNum_++;
 
714
        cmd_ = nullptr;  // will be set on the next begin
 
715
        push_ = nullptr;
 
716
 
 
717
        DirtyDynamicState();
 
718
}
 
719
 
 
720
VkDescriptorSet Thin3DVKContext::GetOrCreateDescriptorSet(VkBuffer buf) {
 
721
        DescriptorSetKey key;
 
722
 
 
723
        FrameData *frame = &frame_[frameNum_ & 1];
 
724
 
 
725
        key.texture_ = boundTextures_[0];
 
726
        key.sampler_ = boundSamplers_[0];
 
727
        key.buffer_ = buf;
 
728
 
 
729
        auto iter = frame->descSets_.find(key);
 
730
        if (iter != frame->descSets_.end()) {
 
731
                return iter->second;
 
732
        }
 
733
 
 
734
        VkDescriptorSet descSet;
 
735
        VkDescriptorSetAllocateInfo alloc = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
 
736
        alloc.descriptorPool = frame->descriptorPool;
 
737
        alloc.pSetLayouts = &descriptorSetLayout_;
 
738
        alloc.descriptorSetCount = 1;
 
739
        VkResult res = vkAllocateDescriptorSets(device_, &alloc, &descSet);
 
740
        assert(VK_SUCCESS == res);
 
741
 
 
742
        VkDescriptorBufferInfo bufferDesc;
 
743
        bufferDesc.buffer = buf;
 
744
        bufferDesc.offset = 0;
 
745
        bufferDesc.range = curShaderSet_->GetUBOSize();
 
746
 
 
747
        VkDescriptorImageInfo imageDesc;
 
748
        imageDesc.imageView = boundTextures_[0]->GetImageView();
 
749
        imageDesc.sampler = boundSamplers_[0]->GetSampler();
 
750
        imageDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
 
751
 
 
752
        VkWriteDescriptorSet writes[2] = {};
 
753
        writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 
754
        writes[0].dstSet = descSet;
 
755
        writes[0].dstArrayElement = 0;
 
756
        writes[0].dstBinding = 0;
 
757
        writes[0].pBufferInfo = &bufferDesc;
 
758
        writes[0].pImageInfo = nullptr;
 
759
        writes[0].pTexelBufferView = nullptr;
 
760
        writes[0].descriptorCount = 1;
 
761
        writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
 
762
 
 
763
        writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 
764
        writes[1].dstSet = descSet;
 
765
        writes[1].dstArrayElement = 0;
 
766
        writes[1].dstBinding = 1;
 
767
        writes[1].pBufferInfo = nullptr;
 
768
        writes[1].pImageInfo = &imageDesc;
 
769
        writes[1].pTexelBufferView = nullptr;
 
770
        writes[1].descriptorCount = 1;
 
771
        writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
 
772
 
 
773
        vkUpdateDescriptorSets(device_, 2, writes, 0, nullptr);
 
774
 
 
775
        frame->descSets_[key] = descSet;
 
776
        return descSet;
 
777
}
 
778
 
 
779
VkPipeline Thin3DVKContext::GetOrCreatePipeline() {
 
780
        PipelineKey key;
 
781
        key.blend = curBlendState_;
 
782
        key.depthStencil = curDepthStencilState_;
 
783
        key.shaderSet = curShaderSet_;
 
784
        key.topology = curPrim_;
 
785
        key.cullMode = curCullMode_;
 
786
 
 
787
        auto iter = pipelines_.find(key);
 
788
        if (iter != pipelines_.end()) {
 
789
                return iter->second;
 
790
        }
 
791
 
 
792
        VkPipelineShaderStageCreateInfo stages[2];
 
793
        stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 
794
        stages[0].pNext = nullptr;
 
795
        stages[0].pSpecializationInfo = nullptr;
 
796
        stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
 
797
        stages[0].module = curShaderSet_->vshader->Get();
 
798
        stages[0].pName = "main";
 
799
        stages[0].flags = 0;
 
800
 
 
801
        stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
 
802
        stages[1].pNext = nullptr;
 
803
        stages[1].pSpecializationInfo = nullptr;
 
804
        stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
 
805
        stages[1].module = curShaderSet_->fshader->Get();
 
806
        stages[1].pName = "main";
 
807
        stages[1].flags = 0;
 
808
 
 
809
        VkPipelineColorBlendStateCreateInfo colorBlend;
 
810
        VkPipelineColorBlendAttachmentState attachment0;
 
811
        curBlendState_->ToVulkan(&colorBlend, &attachment0);
 
812
 
 
813
        VkPipelineDepthStencilStateCreateInfo depthStencil;
 
814
        curDepthStencilState_->ToVulkan(&depthStencil);
 
815
 
 
816
        VkPipelineVertexInputStateCreateInfo vertex;
 
817
        VkVertexInputAttributeDescription attrDescs[4];
 
818
        VkVertexInputBindingDescription bindDescs[1];
 
819
        curVertexFormat_->ToVulkan(&vertex, attrDescs, bindDescs);
 
820
 
 
821
        VkPipelineInputAssemblyStateCreateInfo inputAssembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
 
822
        inputAssembly.topology = curPrim_;
 
823
        inputAssembly.primitiveRestartEnable = false;
 
824
 
 
825
        VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
 
826
        VkPipelineDynamicStateCreateInfo dynamicInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
 
827
        dynamicInfo.dynamicStateCount = ARRAY_SIZE(dynamics);
 
828
        dynamicInfo.pDynamicStates = dynamics;
 
829
 
 
830
        VkPipelineRasterizationStateCreateInfo raster = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
 
831
        switch (curCullMode_) {
 
832
        case NO_CULL: raster.cullMode = VK_CULL_MODE_NONE; break;
 
833
        case CW: raster.cullMode = VK_CULL_MODE_BACK_BIT; break;
 
834
        default:
 
835
        case CCW: raster.cullMode = VK_CULL_MODE_FRONT_BIT; break;
 
836
        }
 
837
        raster.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
 
838
        raster.polygonMode = VK_POLYGON_MODE_FILL;
 
839
        raster.rasterizerDiscardEnable = false;
 
840
        raster.lineWidth = 1.0f;
 
841
        raster.depthBiasClamp = 0.0f;
 
842
        raster.depthBiasEnable = false;
 
843
        raster.depthClampEnable = false;
 
844
        raster.depthBiasSlopeFactor = 0.0;
 
845
 
 
846
        VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
 
847
        ms.pNext = nullptr;
 
848
        ms.pSampleMask = nullptr;
 
849
        ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
 
850
 
 
851
        VkPipelineViewportStateCreateInfo vs = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
 
852
        vs.pNext = nullptr;
 
853
        vs.viewportCount = 1;
 
854
        vs.scissorCount = 1;
 
855
        vs.pViewports = nullptr;  // dynamic
 
856
        vs.pScissors = nullptr;  // dynamic
 
857
 
 
858
        VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
 
859
        info.pNext = nullptr;
 
860
        info.flags = 0;
 
861
        info.stageCount = 2;
 
862
        info.pStages = stages;
 
863
        info.pColorBlendState = &colorBlend;
 
864
        info.pDepthStencilState = &depthStencil;
 
865
        info.pDynamicState = &dynamicInfo;
 
866
        info.pInputAssemblyState = &inputAssembly;
 
867
        info.pTessellationState = nullptr;
 
868
        info.pMultisampleState = &ms;
 
869
        info.pVertexInputState = &vertex;
 
870
        info.pRasterizationState = &raster;
 
871
        info.pViewportState = &vs;  // Must set viewport and scissor counts even if we set the actual state dynamically.
 
872
        info.layout = pipelineLayout_;
 
873
        info.subpass = 0;
 
874
        info.renderPass = vulkan_->GetSurfaceRenderPass();
 
875
 
 
876
        // OK, need to create a new pipeline.
 
877
        VkPipeline pipeline;
 
878
        VkResult result = vkCreateGraphicsPipelines(device_, pipelineCache_, 1, &info, nullptr, &pipeline);
 
879
        if (result != VK_SUCCESS) {
 
880
                ELOG("Failed to create graphics pipeline");
 
881
                return VK_NULL_HANDLE;
 
882
        }
 
883
        
 
884
        pipelines_.insert(std::make_pair(key, pipeline));
 
885
        return pipeline;
 
886
}
 
887
 
 
888
void Thin3DVKContext::SetScissorRect(int left, int top, int width, int height) {
 
889
        scissor_.offset.x = left;
 
890
        scissor_.offset.y = top;
 
891
        scissor_.extent.width = width;
 
892
        scissor_.extent.height = height;
 
893
        scissorDirty_ = true;
 
894
}
 
895
 
 
896
void Thin3DVKContext::SetViewports(int count, T3DViewport *viewports) {
 
897
        viewport_.x = viewports[0].TopLeftX;
 
898
        viewport_.y = viewports[0].TopLeftY;
 
899
        viewport_.width = viewports[0].Width;
 
900
        viewport_.height = viewports[0].Height;
 
901
        viewport_.minDepth = viewports[0].MinDepth;
 
902
        viewport_.maxDepth = viewports[0].MaxDepth;
 
903
        viewportDirty_ = true;
 
904
}
 
905
 
 
906
void Thin3DVKContext::ApplyDynamicState() {
 
907
        if (scissorDirty_) {
 
908
                if (scissorEnabled_) {
 
909
                        vkCmdSetScissor(cmd_, 0, 1, &scissor_);
 
910
                } else {
 
911
                        vkCmdSetScissor(cmd_, 0, 1, &noScissor_);
 
912
                }
 
913
                scissorDirty_ = false;
 
914
        }
 
915
        if (viewportDirty_) {
 
916
                vkCmdSetViewport(cmd_, 0, 1, &viewport_);
 
917
                viewportDirty_ = false;
 
918
        }
 
919
}
 
920
 
 
921
void Thin3DVKContext::DirtyDynamicState() {
 
922
        scissorDirty_ = true;
 
923
        viewportDirty_ = true;
 
924
}
 
925
 
 
926
Thin3DVertexFormat *Thin3DVKContext::CreateVertexFormat(const std::vector<Thin3DVertexComponent> &components, int stride, Thin3DShader *vshader) {
 
927
        Thin3DVKVertexFormat *fmt = new Thin3DVKVertexFormat();
 
928
        fmt->components_ = components;
 
929
        fmt->stride_ = stride;
 
930
        return fmt;
 
931
}
 
932
 
 
933
Thin3DTexture *Thin3DVKContext::CreateTexture() {
 
934
        return new Thin3DVKTexture(vulkan_);
 
935
}
 
936
 
 
937
Thin3DTexture *Thin3DVKContext::CreateTexture(T3DTextureType type, T3DImageFormat format, int width, int height, int depth, int mipLevels) {
 
938
        return new Thin3DVKTexture(vulkan_, type, format, width, height, depth, mipLevels);
 
939
}
 
940
 
 
941
void Thin3DVKTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
 
942
        int bpp;
 
943
        VkFormat vulkanFormat = FormatToVulkan(format_, &bpp);
 
944
        int bytesPerPixel = bpp / 8;
 
945
        vkTex_->Create(width, height, vulkanFormat);
 
946
        int rowPitch;
 
947
        uint8_t *dstData = vkTex_->Lock(0, &rowPitch);
 
948
        for (int y = 0; y < height; y++) {
 
949
                memcpy(dstData + rowPitch * y, data + stride * y, width * bytesPerPixel);
 
950
        }
 
951
        vkTex_->Unlock();
 
952
}
 
953
 
 
954
void Thin3DVKTexture::Finalize(int zim_flags) {
 
955
        // TODO
 
956
}
 
957
 
 
958
Thin3DDepthStencilState *Thin3DVKContext::CreateDepthStencilState(bool depthTestEnabled, bool depthWriteEnabled, T3DComparison depthCompare) {
 
959
        Thin3DVKDepthStencilState *ds = new Thin3DVKDepthStencilState();
 
960
        ds->depthTestEnabled = depthTestEnabled;
 
961
        ds->depthWriteEnabled = depthWriteEnabled;
 
962
        ds->depthComp = compToVK[depthCompare];
 
963
        return ds;
 
964
}
 
965
 
 
966
Thin3DBlendState *Thin3DVKContext::CreateBlendState(const T3DBlendStateDesc &desc) {
 
967
        Thin3DVKBlendState *bs = new Thin3DVKBlendState();
 
968
        bs->blendEnabled = desc.enabled;
 
969
        bs->eqCol = blendEqToGL[desc.eqCol];
 
970
        bs->srcCol = blendFactorToVk[desc.srcCol];
 
971
        bs->dstColor = blendFactorToVk[desc.dstCol];
 
972
        bs->eqAlpha = blendEqToGL[desc.eqAlpha];
 
973
        bs->srcAlpha = blendFactorToVk[desc.srcAlpha];
 
974
        bs->dstAlpha = blendFactorToVk[desc.dstAlpha];
 
975
        bs->logicEnabled = desc.logicEnabled;
 
976
        bs->logicOp = logicOpToVK[desc.logicOp];
 
977
        return bs;
 
978
}
 
979
 
 
980
Thin3DBuffer *Thin3DVKContext::CreateBuffer(size_t size, uint32_t usageFlags) {
 
981
        return new Thin3DVKBuffer(size, usageFlags);
 
982
}
 
983
 
 
984
Thin3DShaderSet *Thin3DVKContext::CreateShaderSet(Thin3DShader *vshader, Thin3DShader *fshader) {
 
985
        if (!vshader || !fshader) {
 
986
                ELOG("ShaderSet requires both a valid vertex and a fragment shader: %p %p", vshader, fshader);
 
987
                return NULL;
 
988
        }
 
989
        Thin3DVKShaderSet *shaderSet = new Thin3DVKShaderSet();
 
990
        vshader->AddRef();
 
991
        fshader->AddRef();
 
992
        shaderSet->vshader = static_cast<Thin3DVKShader *>(vshader);
 
993
        shaderSet->fshader = static_cast<Thin3DVKShader *>(fshader);
 
994
        if (shaderSet->Link()) {
 
995
                return shaderSet;
 
996
        } else {
 
997
                delete shaderSet;
 
998
                return NULL;
 
999
        }
 
1000
}
 
1001
 
 
1002
void Thin3DVKContext::SetTextures(int start, int count, Thin3DTexture **textures) {
 
1003
        for (int i = start; i < start + count; i++) {
 
1004
                boundTextures_[i] = static_cast<Thin3DVKTexture *>(textures[i]);
 
1005
        }
 
1006
}
 
1007
 
 
1008
Thin3DShader *Thin3DVKContext::CreateVertexShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) {
 
1009
        Thin3DVKShader *shader = new Thin3DVKShader(false);
 
1010
        if (shader->Compile(vulkan_, vulkan_source)) {
 
1011
                return shader;
 
1012
        } else {
 
1013
                ELOG("Failed to compile shader: %s", vulkan_source);
 
1014
                shader->Release();
 
1015
                return nullptr;
 
1016
        }
 
1017
}
 
1018
 
 
1019
Thin3DShader *Thin3DVKContext::CreateFragmentShader(const char *glsl_source, const char *hlsl_source, const char *vulkan_source) {
 
1020
        Thin3DVKShader *shader = new Thin3DVKShader(true);
 
1021
        if (shader->Compile(vulkan_, vulkan_source)) {
 
1022
                return shader;
 
1023
        } else {
 
1024
                ELOG("Failed to compile shader: %s", vulkan_source);
 
1025
                shader->Release();
 
1026
                return nullptr;
 
1027
        }
 
1028
}
 
1029
 
 
1030
bool Thin3DVKShaderSet::Link() {
 
1031
        // There is no link step. However, we will create and cache Pipeline objects in the device context.
 
1032
        return true;
 
1033
}
 
1034
 
 
1035
int Thin3DVKShaderSet::GetUniformLoc(const char *name) {
 
1036
        int loc = -1;
 
1037
 
 
1038
        // HACK! As we only use one uniform we hardcode it.
 
1039
        if (!strcmp(name, "WorldViewProj")) {
 
1040
                return 0;
 
1041
        }
 
1042
 
 
1043
        return loc;
 
1044
}
 
1045
 
 
1046
void Thin3DVKShaderSet::SetVector(const char *name, float *value, int n) {
 
1047
        // TODO: Implement
 
1048
}
 
1049
 
 
1050
void Thin3DVKShaderSet::SetMatrix4x4(const char *name, const float value[16]) {
 
1051
        int loc = GetUniformLoc(name);
 
1052
        if (loc != -1) {
 
1053
                memcpy(ubo_ + loc, value, 16 * sizeof(float));
 
1054
        }
 
1055
}
 
1056
 
 
1057
void Thin3DVKContext::SetRenderState(T3DRenderState rs, uint32_t value) {
 
1058
        switch (rs) {
 
1059
        case T3DRenderState::CULL_MODE:
 
1060
                curCullMode_ = (T3DCullMode)value;
 
1061
                break;
 
1062
        }
 
1063
}
 
1064
 
 
1065
void Thin3DVKContext::Draw(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, Thin3DBuffer *vdata, int vertexCount, int offset) {
 
1066
        ApplyDynamicState();
 
1067
        
 
1068
        curPrim_ = primToVK[prim];
 
1069
        curShaderSet_ = (Thin3DVKShaderSet *)shaderSet;
 
1070
        curVertexFormat_ = (Thin3DVKVertexFormat *)format;
 
1071
        Thin3DVKBuffer *vbuf = static_cast<Thin3DVKBuffer *>(vdata);
 
1072
 
 
1073
        VkBuffer vulkanVbuf;
 
1074
        VkBuffer vulkanUBObuf;
 
1075
        uint32_t ubo_offset = (uint32_t)curShaderSet_->PushUBO(push_, vulkan_, &vulkanUBObuf);
 
1076
        size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), &vulkanVbuf);
 
1077
 
 
1078
        VkPipeline pipeline = GetOrCreatePipeline();
 
1079
        vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
 
1080
        VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
 
1081
        vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
 
1082
        VkBuffer buffers[1] = { vulkanVbuf };
 
1083
        VkDeviceSize offsets[1] = { vbBindOffset };
 
1084
        vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
 
1085
        vkCmdDraw(cmd_, vertexCount, 1, offset, 0);
 
1086
}
 
1087
 
 
1088
void Thin3DVKContext::DrawIndexed(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, Thin3DBuffer *vdata, Thin3DBuffer *idata, int vertexCount, int offset) {
 
1089
        ApplyDynamicState();
 
1090
        
 
1091
        curPrim_ = primToVK[prim];
 
1092
        curShaderSet_ = (Thin3DVKShaderSet *)shaderSet;
 
1093
        curVertexFormat_ = (Thin3DVKVertexFormat *)format;
 
1094
 
 
1095
        Thin3DVKBuffer *ibuf = static_cast<Thin3DVKBuffer *>(idata);
 
1096
        Thin3DVKBuffer *vbuf = static_cast<Thin3DVKBuffer *>(vdata);
 
1097
 
 
1098
        VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
 
1099
        uint32_t ubo_offset = (uint32_t)curShaderSet_->PushUBO(push_, vulkan_, &vulkanUBObuf);
 
1100
        size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), &vulkanVbuf);
 
1101
        size_t ibBindOffset = push_->Push(ibuf->GetData(), ibuf->GetSize(), &vulkanIbuf);
 
1102
 
 
1103
        VkPipeline pipeline = GetOrCreatePipeline();
 
1104
        vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
 
1105
 
 
1106
        VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
 
1107
        vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
 
1108
 
 
1109
        VkBuffer buffers[1] = { vulkanVbuf };
 
1110
        VkDeviceSize offsets[1] = { vbBindOffset };
 
1111
        vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
 
1112
 
 
1113
        vkCmdBindIndexBuffer(cmd_, vulkanIbuf, ibBindOffset, VK_INDEX_TYPE_UINT32);
 
1114
        vkCmdDrawIndexed(cmd_, vertexCount, 1, 0, offset, 0);
 
1115
}
 
1116
 
 
1117
void Thin3DVKContext::DrawUP(T3DPrimitive prim, Thin3DShaderSet *shaderSet, Thin3DVertexFormat *format, const void *vdata, int vertexCount) {
 
1118
        ApplyDynamicState();
 
1119
 
 
1120
        curPrim_ = primToVK[prim];
 
1121
        curShaderSet_ = (Thin3DVKShaderSet *)shaderSet;
 
1122
        curVertexFormat_ = (Thin3DVKVertexFormat *)format;
 
1123
 
 
1124
        VkBuffer vulkanVbuf, vulkanUBObuf;
 
1125
        size_t vbBindOffset = push_->Push(vdata, vertexCount * curVertexFormat_->stride_, &vulkanVbuf);
 
1126
        uint32_t ubo_offset = (uint32_t)curShaderSet_->PushUBO(push_, vulkan_, &vulkanUBObuf);
 
1127
 
 
1128
        VkPipeline pipeline = GetOrCreatePipeline();
 
1129
        vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
 
1130
 
 
1131
        VkBuffer buffers[1] = { vulkanVbuf };
 
1132
        VkDeviceSize offsets[1] = { vbBindOffset };
 
1133
        vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
 
1134
 
 
1135
        VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
 
1136
        vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
 
1137
        vkCmdDraw(cmd_, vertexCount, 1, 0, 0);
 
1138
}
 
1139
 
 
1140
void Thin3DVKContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) {
 
1141
        if (mask & T3DClear::COLOR) {
 
1142
                VkClearColorValue col;
 
1143
                Uint8x4ToFloat4(colorval, col.float32);
 
1144
 
 
1145
                /*
 
1146
                VkRect3D rect;
 
1147
                rect.extent.width =
 
1148
                vkCmdClearColorAttachment(cmdBuf_, 0, imageLayout_, &col, 1, nullptr);
 
1149
                */
 
1150
        }
 
1151
        if (mask & (T3DClear::DEPTH | T3DClear::STENCIL)) {
 
1152
 
 
1153
        }
 
1154
}
 
1155
 
 
1156
Thin3DContext *T3DCreateVulkanContext(VulkanContext *vulkan) {
 
1157
        return new Thin3DVKContext(vulkan);
 
1158
}
 
1159
 
 
1160
void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 available, VkBool32 enabled) {
 
1161
        char buf[512];
 
1162
        snprintf(buf, sizeof(buf), "%s: Available: %d Enabled: %d", name, (int)available, (int)enabled);
 
1163
        features.push_back(buf);
 
1164
}
 
1165
 
 
1166
std::vector<std::string> Thin3DVKContext::GetFeatureList() {
 
1167
        const VkPhysicalDeviceFeatures &available = vulkan_->GetFeaturesAvailable();
 
1168
        const VkPhysicalDeviceFeatures &enabled = vulkan_->GetFeaturesEnabled();
 
1169
        std::vector<std::string> features;
 
1170
        AddFeature(features, "dualSrcBlend", available.dualSrcBlend, enabled.dualSrcBlend);
 
1171
        AddFeature(features, "logicOp", available.logicOp, enabled.logicOp);
 
1172
        AddFeature(features, "geometryShader", available.geometryShader, enabled.geometryShader);
 
1173
        AddFeature(features, "depthBounds", available.depthBounds, enabled.depthBounds);
 
1174
        AddFeature(features, "depthClamp", available.depthClamp, enabled.depthClamp);
 
1175
        AddFeature(features, "fillModeNonSolid", available.fillModeNonSolid, enabled.fillModeNonSolid);
 
1176
        AddFeature(features, "largePoints", available.largePoints, enabled.largePoints);
 
1177
        AddFeature(features, "wideLines", available.wideLines, enabled.wideLines);
 
1178
        AddFeature(features, "pipelineStatisticsQuery", available.pipelineStatisticsQuery, enabled.pipelineStatisticsQuery);
 
1179
        AddFeature(features, "samplerAnisotropy", available.samplerAnisotropy, enabled.samplerAnisotropy);
 
1180
        AddFeature(features, "textureCompressionBC", available.textureCompressionBC, enabled.textureCompressionBC);
 
1181
        AddFeature(features, "textureCompressionETC2", available.textureCompressionETC2, enabled.textureCompressionETC2);
 
1182
        AddFeature(features, "textureCompressionASTC_LDR", available.textureCompressionASTC_LDR, enabled.textureCompressionASTC_LDR);
 
1183
        AddFeature(features, "shaderClipDistance", available.shaderClipDistance, enabled.shaderClipDistance);
 
1184
        AddFeature(features, "shaderCullDistance", available.shaderCullDistance, enabled.shaderCullDistance);
 
1185
        AddFeature(features, "occlusionQueryPrecise", available.occlusionQueryPrecise, enabled.occlusionQueryPrecise);
 
1186
        AddFeature(features, "multiDrawIndirect", available.multiDrawIndirect, enabled.multiDrawIndirect);
 
1187
 
 
1188
        // Also list texture formats and their properties.
 
1189
        for (int i = VK_FORMAT_BEGIN_RANGE; i <= VK_FORMAT_END_RANGE; i++) {
 
1190
                // TODO
 
1191
        }
 
1192
 
 
1193
        return features;
 
1194
}