2015-10-10 16:41:19 +02:00
|
|
|
// Copyright (c) 2015- PPSSPP Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0 or later versions.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official git repository and contact information can be found at
|
|
|
|
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
|
|
|
|
2016-12-25 18:18:19 +01:00
|
|
|
#include <cstdio>
|
2015-10-10 16:41:19 +02:00
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2016-01-06 12:52:08 +01:00
|
|
|
#include "Common/Vulkan/SPIRVDisasm.h"
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
#include "base/logging.h"
|
|
|
|
#include "base/display.h"
|
2016-01-03 14:00:05 +01:00
|
|
|
#include "base/stringutil.h"
|
2015-10-10 16:41:19 +02:00
|
|
|
#include "image/zim_load.h"
|
|
|
|
#include "math/lin/matrix4x4.h"
|
|
|
|
#include "math/dataconv.h"
|
|
|
|
#include "thin3d/thin3d.h"
|
2016-03-17 11:56:43 +01:00
|
|
|
|
2016-02-21 20:21:24 +01:00
|
|
|
#include "Common/Vulkan/VulkanContext.h"
|
2016-03-17 11:56:43 +01:00
|
|
|
#include "Common/Vulkan/VulkanImage.h"
|
2016-03-20 09:35:10 +01:00
|
|
|
#include "Common/Vulkan/VulkanMemory.h"
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point.
|
2016-01-02 02:08:05 +01:00
|
|
|
// binding 0 - uniform data
|
|
|
|
// binding 1 - sampler
|
|
|
|
//
|
|
|
|
// Vertex data lives in a separate namespace (location = 0, 1, etc)
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-02-21 18:05:01 +01:00
|
|
|
#include "Common/Vulkan/VulkanLoader.h"
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-25 18:18:19 +01:00
|
|
|
namespace Draw {
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
// This can actually be replaced with a cast as the values are in the right order.
|
|
|
|
static const VkCompareOp compToVK[] = {
|
|
|
|
VK_COMPARE_OP_NEVER,
|
|
|
|
VK_COMPARE_OP_LESS,
|
|
|
|
VK_COMPARE_OP_EQUAL,
|
|
|
|
VK_COMPARE_OP_LESS_OR_EQUAL,
|
|
|
|
VK_COMPARE_OP_GREATER,
|
|
|
|
VK_COMPARE_OP_NOT_EQUAL,
|
|
|
|
VK_COMPARE_OP_GREATER_OR_EQUAL,
|
|
|
|
VK_COMPARE_OP_ALWAYS
|
|
|
|
};
|
|
|
|
|
|
|
|
// So can this.
|
2016-12-26 18:32:52 +01:00
|
|
|
static const VkBlendOp blendEqToVk[] = {
|
2015-10-10 16:41:19 +02:00
|
|
|
VK_BLEND_OP_ADD,
|
|
|
|
VK_BLEND_OP_SUBTRACT,
|
|
|
|
VK_BLEND_OP_REVERSE_SUBTRACT,
|
2016-12-26 23:51:17 +01:00
|
|
|
VK_BLEND_OP_MIN,
|
|
|
|
VK_BLEND_OP_MAX,
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static const VkBlendFactor blendFactorToVk[] = {
|
|
|
|
VK_BLEND_FACTOR_ZERO,
|
|
|
|
VK_BLEND_FACTOR_ONE,
|
|
|
|
VK_BLEND_FACTOR_SRC_COLOR,
|
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
|
|
|
|
VK_BLEND_FACTOR_DST_COLOR,
|
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
|
2016-12-26 23:51:17 +01:00
|
|
|
VK_BLEND_FACTOR_SRC_ALPHA,
|
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
|
|
|
VK_BLEND_FACTOR_DST_ALPHA,
|
2015-10-10 16:41:19 +02:00
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
|
|
|
|
VK_BLEND_FACTOR_CONSTANT_COLOR,
|
2016-12-26 23:51:17 +01:00
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
|
|
|
|
VK_BLEND_FACTOR_CONSTANT_ALPHA,
|
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
|
|
|
|
VK_BLEND_FACTOR_SRC1_COLOR,
|
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
|
|
|
|
VK_BLEND_FACTOR_SRC1_ALPHA,
|
|
|
|
VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static const VkLogicOp logicOpToVK[] = {
|
|
|
|
VK_LOGIC_OP_CLEAR,
|
|
|
|
VK_LOGIC_OP_SET,
|
|
|
|
VK_LOGIC_OP_COPY,
|
|
|
|
VK_LOGIC_OP_COPY_INVERTED,
|
|
|
|
VK_LOGIC_OP_NO_OP,
|
|
|
|
VK_LOGIC_OP_INVERT,
|
|
|
|
VK_LOGIC_OP_AND,
|
|
|
|
VK_LOGIC_OP_NAND,
|
|
|
|
VK_LOGIC_OP_OR,
|
|
|
|
VK_LOGIC_OP_NOR,
|
|
|
|
VK_LOGIC_OP_XOR,
|
|
|
|
VK_LOGIC_OP_EQUIVALENT,
|
|
|
|
VK_LOGIC_OP_AND_REVERSE,
|
|
|
|
VK_LOGIC_OP_AND_INVERTED,
|
|
|
|
VK_LOGIC_OP_OR_REVERSE,
|
|
|
|
VK_LOGIC_OP_OR_INVERTED,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const VkPrimitiveTopology primToVK[] = {
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
2016-12-25 18:52:05 +01:00
|
|
|
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP,
|
2015-10-10 16:41:19 +02:00
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
2016-12-25 18:52:05 +01:00
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
|
2017-01-21 13:11:03 +01:00
|
|
|
// Tesselation shader primitive.
|
2016-12-25 18:52:05 +01:00
|
|
|
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
|
2017-01-21 13:11:03 +01:00
|
|
|
// The rest are for geometry shaders only.
|
2016-12-25 18:52:05 +01:00
|
|
|
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY,
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
2016-12-26 23:11:31 +01:00
|
|
|
|
|
|
|
static const VkStencilOp stencilOpToVK[8] = {
|
|
|
|
VK_STENCIL_OP_KEEP,
|
|
|
|
VK_STENCIL_OP_ZERO,
|
|
|
|
VK_STENCIL_OP_REPLACE,
|
|
|
|
VK_STENCIL_OP_INCREMENT_AND_CLAMP,
|
|
|
|
VK_STENCIL_OP_DECREMENT_AND_CLAMP,
|
|
|
|
VK_STENCIL_OP_INVERT,
|
|
|
|
VK_STENCIL_OP_INCREMENT_AND_WRAP,
|
|
|
|
VK_STENCIL_OP_DECREMENT_AND_WRAP,
|
|
|
|
};
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
static inline void Uint8x4ToFloat4(uint32_t u, float f[4]) {
|
|
|
|
f[0] = ((u >> 0) & 0xFF) * (1.0f / 255.0f);
|
|
|
|
f[1] = ((u >> 8) & 0xFF) * (1.0f / 255.0f);
|
|
|
|
f[2] = ((u >> 16) & 0xFF) * (1.0f / 255.0f);
|
|
|
|
f[3] = ((u >> 24) & 0xFF) * (1.0f / 255.0f);
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
class VKBlendState : public BlendState {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-26 23:11:31 +01:00
|
|
|
VkPipelineColorBlendStateCreateInfo info{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
|
2016-12-26 18:32:52 +01:00
|
|
|
std::vector<VkPipelineColorBlendAttachmentState> attachments;
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
class VKDepthStencilState : public DepthStencilState {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-26 23:11:31 +01:00
|
|
|
VkPipelineDepthStencilStateCreateInfo info{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
class VKRasterState : public RasterState {
|
2016-12-23 23:46:11 +01:00
|
|
|
public:
|
2016-12-25 22:24:14 +01:00
|
|
|
VKRasterState(VulkanContext *vulkan, const RasterStateDesc &desc) {
|
2016-12-23 23:46:11 +01:00
|
|
|
cullFace = desc.cull;
|
2016-12-27 15:52:03 +01:00
|
|
|
frontFace = desc.frontFace;
|
2016-12-23 23:46:11 +01:00
|
|
|
}
|
2016-12-25 18:52:05 +01:00
|
|
|
Facing frontFace;
|
|
|
|
CullMode cullFace;
|
2016-12-23 23:46:11 +01:00
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
void ToVulkan(VkPipelineRasterizationStateCreateInfo *info) const {
|
2016-12-23 23:46:11 +01:00
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
info->sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
2016-12-25 18:52:05 +01:00
|
|
|
info->frontFace = frontFace == Facing::CCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE;
|
2016-12-23 23:46:11 +01:00
|
|
|
switch (cullFace) {
|
2016-12-25 18:52:05 +01:00
|
|
|
case CullMode::BACK: info->cullMode = VK_CULL_MODE_BACK_BIT; break;
|
|
|
|
case CullMode::FRONT: info->cullMode = VK_CULL_MODE_FRONT_BIT; break;
|
|
|
|
case CullMode::FRONT_AND_BACK: info->cullMode = VK_CULL_MODE_FRONT_AND_BACK; break;
|
|
|
|
case CullMode::NONE: info->cullMode = VK_CULL_MODE_NONE; break;
|
2016-12-23 23:46:11 +01:00
|
|
|
}
|
|
|
|
info->polygonMode = VK_POLYGON_MODE_FILL;
|
|
|
|
info->lineWidth = 1.0f;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
|
|
|
|
// to avoid synchronization issues.
|
2017-01-17 23:14:47 +07:00
|
|
|
class VKBuffer : public Buffer {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2017-01-17 23:14:47 +07:00
|
|
|
VKBuffer(size_t size, uint32_t flags) : dataSize_(size) {
|
2015-10-10 16:41:19 +02:00
|
|
|
data_ = new uint8_t[size];
|
|
|
|
}
|
2017-01-17 23:14:47 +07:00
|
|
|
~VKBuffer() override {
|
2015-10-10 16:41:19 +02:00
|
|
|
delete[] data_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetData(const uint8_t *data, size_t size) override {
|
|
|
|
delete[] data_;
|
|
|
|
dataSize_ = size;
|
|
|
|
data_ = new uint8_t[size];
|
|
|
|
if (data) {
|
|
|
|
memcpy(data_, data, size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SubData(const uint8_t *data, size_t offset, size_t size) override {
|
|
|
|
memcpy(data_, data_ + offset, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t GetSize() const { return dataSize_; }
|
|
|
|
const uint8_t *GetData() const { return data_; }
|
|
|
|
|
2017-01-17 23:14:47 +07:00
|
|
|
private:
|
2015-10-10 16:41:19 +02:00
|
|
|
uint8_t *data_;
|
|
|
|
size_t dataSize_;
|
|
|
|
};
|
|
|
|
|
2016-12-25 22:24:14 +01:00
|
|
|
VkShaderStageFlagBits StageToVulkan(ShaderStage stage) {
|
|
|
|
switch (stage) {
|
|
|
|
case ShaderStage::VERTEX: return VK_SHADER_STAGE_VERTEX_BIT;
|
|
|
|
case ShaderStage::GEOMETRY: return VK_SHADER_STAGE_GEOMETRY_BIT;
|
|
|
|
case ShaderStage::COMPUTE: return VK_SHADER_STAGE_COMPUTE_BIT;
|
|
|
|
case ShaderStage::EVALUATION: return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
|
|
|
|
case ShaderStage::CONTROL: return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
|
|
|
|
default:
|
|
|
|
case ShaderStage::FRAGMENT: return VK_SHADER_STAGE_FRAGMENT_BIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 13:42:53 +01:00
|
|
|
// Not registering this as a resource holder, instead the pipeline is registered. It will
|
2015-10-10 16:41:19 +02:00
|
|
|
// invoke Compile again to recreate the shader then link them together.
|
2016-12-25 22:24:14 +01:00
|
|
|
class VKShaderModule : public ShaderModule {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-25 22:24:14 +01:00
|
|
|
VKShaderModule(ShaderStage stage) : module_(VK_NULL_HANDLE), ok_(false), stage_(stage) {
|
|
|
|
vkstage_ = StageToVulkan(stage);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
2016-12-27 17:38:26 +01:00
|
|
|
bool Compile(VulkanContext *vulkan, ShaderLanguage language, const uint8_t *data, size_t size);
|
2015-10-10 16:41:19 +02:00
|
|
|
const std::string &GetSource() const { return source_; }
|
2016-12-25 22:24:14 +01:00
|
|
|
~VKShaderModule() {
|
2016-05-14 16:29:40 +02:00
|
|
|
if (module_) {
|
|
|
|
vkDestroyShaderModule(device_, module_, nullptr);
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
VkShaderModule Get() const { return module_; }
|
2016-12-25 22:24:14 +01:00
|
|
|
ShaderStage GetStage() const override {
|
|
|
|
return stage_;
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
private:
|
2016-03-21 00:03:34 -07:00
|
|
|
VkDevice device_;
|
2015-10-10 16:41:19 +02:00
|
|
|
VkShaderModule module_;
|
2016-12-25 22:24:14 +01:00
|
|
|
VkShaderStageFlagBits vkstage_;
|
2015-10-10 16:41:19 +02:00
|
|
|
bool ok_;
|
2016-12-25 22:24:14 +01:00
|
|
|
ShaderStage stage_;
|
2015-10-10 16:41:19 +02:00
|
|
|
std::string source_; // So we can recompile in case of context loss.
|
|
|
|
};
|
|
|
|
|
2016-12-27 17:38:26 +01:00
|
|
|
bool VKShaderModule::Compile(VulkanContext *vulkan, ShaderLanguage language, const uint8_t *data, size_t size) {
|
2016-03-21 00:03:34 -07:00
|
|
|
// We'll need this to free it later.
|
|
|
|
device_ = vulkan->GetDevice();
|
2016-12-27 17:38:26 +01:00
|
|
|
this->source_ = (const char *)data;
|
2015-10-10 16:41:19 +02:00
|
|
|
std::vector<uint32_t> spirv;
|
2016-12-27 17:38:26 +01:00
|
|
|
if (!GLSLtoSPV(vkstage_, source_.c_str(), spirv)) {
|
2015-10-10 16:41:19 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-01-06 12:52:08 +01:00
|
|
|
// Just for kicks, sanity check the SPIR-V. The disasm isn't perfect
|
|
|
|
// but gives you some idea of what's going on.
|
|
|
|
#if 0
|
|
|
|
std::string disasm;
|
|
|
|
if (DisassembleSPIRV(spirv, &disasm)) {
|
|
|
|
OutputDebugStringA(disasm.c_str());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2016-01-05 21:18:43 +01:00
|
|
|
if (vulkan->CreateShaderModule(spirv, &module_)) {
|
2015-10-10 16:41:19 +02:00
|
|
|
ok_ = true;
|
|
|
|
} else {
|
|
|
|
ok_ = false;
|
|
|
|
}
|
|
|
|
return ok_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-12-25 18:52:05 +01:00
|
|
|
inline VkFormat ConvertVertexDataTypeToVk(DataFormat type) {
|
2015-10-10 16:41:19 +02:00
|
|
|
switch (type) {
|
2016-12-25 21:21:56 +01:00
|
|
|
case DataFormat::R32G32_FLOAT: return VK_FORMAT_R32G32_SFLOAT;
|
|
|
|
case DataFormat::R32G32B32_FLOAT: return VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
case DataFormat::R32G32B32A32_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
|
|
case DataFormat::R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
|
2015-10-10 16:41:19 +02:00
|
|
|
default: return VK_FORMAT_UNDEFINED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 13:22:48 +01:00
|
|
|
class VKInputLayout : public InputLayout {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-26 13:22:48 +01:00
|
|
|
std::vector<VkVertexInputBindingDescription> bindings;
|
|
|
|
std::vector<VkVertexInputAttributeDescription> attributes;
|
|
|
|
VkPipelineVertexInputStateCreateInfo visc;
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
2016-12-26 11:06:17 +01:00
|
|
|
class VKPipeline : public Pipeline {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-26 11:06:17 +01:00
|
|
|
VKPipeline() {
|
2015-10-10 16:41:19 +02:00
|
|
|
// HACK! Hardcoded
|
|
|
|
uboSize_ = 16 * sizeof(float); // WorldViewProj
|
|
|
|
ubo_ = new uint8_t[uboSize_];
|
|
|
|
}
|
2016-12-26 11:06:17 +01:00
|
|
|
~VKPipeline() {
|
2016-01-10 14:24:10 +01:00
|
|
|
delete[] ubo_;
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
// Returns the binding offset, and the VkBuffer to bind.
|
|
|
|
size_t PushUBO(VulkanPushBuffer *buf, VulkanContext *vulkan, VkBuffer *vkbuf) {
|
|
|
|
return buf->PushAligned(ubo_, uboSize_, vulkan->GetPhysicalDeviceProperties().limits.minUniformBufferOffsetAlignment, vkbuf);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int GetUniformLoc(const char *name);
|
|
|
|
|
|
|
|
void SetVector(const char *name, float *value, int n) override;
|
|
|
|
void SetMatrix4x4(const char *name, const float value[16]) override;
|
|
|
|
|
2016-01-02 02:08:05 +01:00
|
|
|
int GetUBOSize() const {
|
|
|
|
return uboSize_;
|
|
|
|
}
|
2017-01-17 19:41:53 +07:00
|
|
|
bool RequiresBuffer() override {
|
2016-12-26 17:03:01 +01:00
|
|
|
return false;
|
|
|
|
}
|
2016-01-02 02:08:05 +01:00
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
VkPipeline vkpipeline;
|
|
|
|
int stride[4];
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
private:
|
|
|
|
uint8_t *ubo_;
|
|
|
|
int uboSize_;
|
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
class VKTexture;
|
|
|
|
class VKSamplerState;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
struct DescriptorSetKey {
|
2016-12-25 21:21:56 +01:00
|
|
|
VKTexture *texture_;
|
|
|
|
VKSamplerState *sampler_;
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer buffer_;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
bool operator < (const DescriptorSetKey &other) const {
|
|
|
|
if (texture_ < other.texture_) return true; else if (texture_ > other.texture_) return false;
|
|
|
|
if (sampler_ < other.sampler_) return true; else if (sampler_ > other.sampler_) return false;
|
2016-01-03 13:27:19 +01:00
|
|
|
if (buffer_ < other.buffer_) return true; else if (buffer_ > other.buffer_) return false;
|
2015-10-10 16:41:19 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
class VKContext : public DrawContext {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-25 21:21:56 +01:00
|
|
|
VKContext(VulkanContext *vulkan);
|
|
|
|
virtual ~VKContext();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-26 17:31:20 +01:00
|
|
|
const DeviceCaps &GetDeviceCaps() const override {
|
|
|
|
return caps_;
|
|
|
|
}
|
2016-12-27 16:33:54 +01:00
|
|
|
uint32_t GetSupportedShaderLanguages() const override {
|
|
|
|
return (uint32_t)ShaderLanguage::GLSL_VULKAN | (uint32_t)ShaderLanguage::SPIRV_VULKAN;
|
|
|
|
}
|
2017-01-19 12:16:36 +07:00
|
|
|
uint32_t GetDataFormatSupport(DataFormat fmt) const override;
|
2016-12-26 17:31:20 +01:00
|
|
|
|
2016-12-25 21:10:46 +01:00
|
|
|
DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) override;
|
2016-12-25 18:52:05 +01:00
|
|
|
BlendState *CreateBlendState(const BlendStateDesc &desc) override;
|
2016-12-26 13:22:48 +01:00
|
|
|
InputLayout *CreateInputLayout(const InputLayoutDesc &desc) override;
|
2016-12-25 20:54:37 +01:00
|
|
|
SamplerState *CreateSamplerState(const SamplerStateDesc &desc) override;
|
2016-12-25 22:24:14 +01:00
|
|
|
RasterState *CreateRasterState(const RasterStateDesc &desc) override;
|
2016-12-26 13:42:53 +01:00
|
|
|
Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc) override;
|
2016-12-27 17:38:26 +01:00
|
|
|
ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize) override;
|
2016-12-25 22:24:14 +01:00
|
|
|
|
2017-01-16 23:43:07 +07:00
|
|
|
Texture *CreateTexture(const TextureDesc &desc) override;
|
2017-02-04 18:46:12 +01:00
|
|
|
Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override;
|
|
|
|
Framebuffer *fbo_create(const FramebufferDesc &desc) override { return nullptr; }
|
|
|
|
|
|
|
|
void fbo_copy_image(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) override {}
|
|
|
|
bool fbo_blit(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter) override { return true; }
|
|
|
|
|
|
|
|
int fbo_preferred_z_bitdepth() override { return 24; }
|
|
|
|
|
|
|
|
// These functions should be self explanatory.
|
|
|
|
void fbo_bind_as_render_target(Framebuffer *fbo) override {}
|
|
|
|
// color must be 0, for now.
|
|
|
|
void fbo_bind_as_texture(Framebuffer *fbo, int binding, FBChannel channelBit, int attachment) override {}
|
|
|
|
void fbo_bind_for_read(Framebuffer *fbo) override {}
|
|
|
|
|
|
|
|
void fbo_bind_backbuffer_as_render_target() override {}
|
|
|
|
uintptr_t fbo_get_api_texture(Framebuffer *fbo, int channelBit, int attachment) override { return 0; }
|
|
|
|
|
|
|
|
void fbo_get_dimensions(Framebuffer *fbo, int *w, int *h) override {}
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
void SetScissorRect(int left, int top, int width, int height) override;
|
2016-12-25 18:52:05 +01:00
|
|
|
void SetViewports(int count, Viewport *viewports) override;
|
2016-12-27 15:52:03 +01:00
|
|
|
void SetBlendFactor(float color[4]) override;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-26 11:16:59 +01:00
|
|
|
void BindSamplerStates(int start, int count, SamplerState **state) override;
|
2016-12-25 20:54:37 +01:00
|
|
|
void BindTextures(int start, int count, Texture **textures) override;
|
2016-12-26 11:16:59 +01:00
|
|
|
void BindPipeline(Pipeline *pipeline) override {
|
|
|
|
curPipeline_ = (VKPipeline *)pipeline;
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2017-01-17 23:14:47 +07:00
|
|
|
// TODO: Make VKBuffers proper buffers, and do a proper binding model. This is just silly.
|
|
|
|
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override {
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
|
curVBuffers_[i + start] = (VKBuffer *)buffers[i];
|
|
|
|
curVBufferOffsets_[i + start] = offsets ? offsets[i] : 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
|
|
|
|
curIBuffer_ = (VKBuffer *)indexBuffer;
|
|
|
|
curIBufferOffset_ = offset;
|
|
|
|
}
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
// TODO: Add more sophisticated draws.
|
2017-01-17 23:14:47 +07:00
|
|
|
void Draw(int vertexCount, int offset) override;
|
|
|
|
void DrawIndexed(int vertexCount, int offset) override;
|
2016-12-26 17:03:01 +01:00
|
|
|
void DrawUP(const void *vdata, int vertexCount) override;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
|
|
|
|
|
2016-04-24 10:57:56 -07:00
|
|
|
void Begin(bool clear, uint32_t colorval, float depthVal, int stencilVal) override;
|
|
|
|
void End() override;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-25 18:52:05 +01:00
|
|
|
std::string GetInfoString(InfoField info) const override {
|
2015-10-10 16:41:19 +02:00
|
|
|
// TODO: Make these actually query the right information
|
|
|
|
switch (info) {
|
2016-01-03 14:00:05 +01:00
|
|
|
case APINAME: return "Vulkan";
|
|
|
|
case VENDORSTRING: return vulkan_->GetPhysicalDeviceProperties().deviceName;
|
|
|
|
case VENDOR: return StringFromFormat("%08x", vulkan_->GetPhysicalDeviceProperties().vendorID);
|
|
|
|
case RENDERER: return StringFromFormat("%08x", vulkan_->GetPhysicalDeviceProperties().driverVersion);
|
2015-10-10 16:41:19 +02:00
|
|
|
case SHADELANGVERSION: return "N/A";;
|
2016-01-03 14:00:05 +01:00
|
|
|
case APIVERSION:
|
|
|
|
{
|
|
|
|
uint32_t ver = vulkan_->GetPhysicalDeviceProperties().apiVersion;
|
|
|
|
return StringFromFormat("%d.%d.%d", ver >> 22, (ver >> 12) & 0x3ff, ver & 0xfff);
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
default: return "?";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkDescriptorSet GetOrCreateDescriptorSet(VkBuffer buffer);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-26 17:31:20 +01:00
|
|
|
std::vector<std::string> GetFeatureList() const override;
|
2016-01-03 14:00:05 +01:00
|
|
|
|
2017-02-05 20:05:03 +01:00
|
|
|
uintptr_t GetNativeObject(NativeObject obj) const override {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
private:
|
|
|
|
void ApplyDynamicState();
|
|
|
|
void DirtyDynamicState();
|
|
|
|
|
|
|
|
VulkanContext *vulkan_;
|
|
|
|
|
2016-12-26 11:06:17 +01:00
|
|
|
VKPipeline *curPipeline_;
|
2017-01-17 23:14:47 +07:00
|
|
|
VKBuffer *curVBuffers_[4];
|
|
|
|
int curVBufferOffsets_[4];
|
|
|
|
VKBuffer *curIBuffer_;
|
|
|
|
int curIBufferOffset_;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
VkDescriptorSetLayout descriptorSetLayout_;
|
|
|
|
VkPipelineLayout pipelineLayout_;
|
|
|
|
VkPipelineCache pipelineCache_;
|
|
|
|
|
|
|
|
VkCommandPool cmdPool_;
|
|
|
|
VkDevice device_;
|
|
|
|
VkQueue queue_;
|
|
|
|
int queueFamilyIndex_;
|
|
|
|
|
|
|
|
// State to apply at the next draw call if viewportDirty or scissorDirty are true.
|
|
|
|
bool viewportDirty_;
|
|
|
|
VkViewport viewport_;
|
|
|
|
bool scissorDirty_;
|
|
|
|
VkRect2D scissor_;
|
|
|
|
|
|
|
|
enum {MAX_BOUND_TEXTURES = 1};
|
2016-12-25 21:21:56 +01:00
|
|
|
VKTexture *boundTextures_[MAX_BOUND_TEXTURES];
|
|
|
|
VKSamplerState *boundSamplers_[MAX_BOUND_TEXTURES];
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
VkCommandBuffer cmd_; // The current one
|
2016-01-03 12:37:05 +01:00
|
|
|
|
|
|
|
struct FrameData {
|
|
|
|
VulkanPushBuffer *pushBuffer;
|
2016-01-03 13:27:19 +01:00
|
|
|
|
|
|
|
// Per-frame descriptor set cache. As it's per frame and reset every frame, we don't need to
|
|
|
|
// worry about invalidating descriptors pointing to deleted textures.
|
|
|
|
std::map<DescriptorSetKey, VkDescriptorSet> descSets_;
|
|
|
|
VkDescriptorPool descriptorPool;
|
2016-01-03 12:37:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
FrameData frame_[2];
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
int frameNum_;
|
|
|
|
VulkanPushBuffer *push_;
|
2016-12-26 17:31:20 +01:00
|
|
|
|
|
|
|
DeviceCaps caps_;
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
2017-01-21 13:11:03 +01:00
|
|
|
static int GetBpp(VkFormat format) {
|
2016-12-26 13:22:48 +01:00
|
|
|
switch (format) {
|
|
|
|
case VK_FORMAT_R8G8B8A8_UNORM:
|
2017-01-21 13:11:03 +01:00
|
|
|
case VK_FORMAT_B8G8R8A8_UNORM:
|
2016-12-26 13:22:48 +01:00
|
|
|
return 32;
|
|
|
|
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
2017-01-21 13:11:03 +01:00
|
|
|
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
|
|
|
|
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
|
|
|
|
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
|
|
|
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
|
|
|
|
case VK_FORMAT_B5G6R5_UNORM_PACK16:
|
|
|
|
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
2016-12-26 13:22:48 +01:00
|
|
|
return 16;
|
|
|
|
case VK_FORMAT_D24_UNORM_S8_UINT:
|
|
|
|
return 32;
|
|
|
|
case VK_FORMAT_D16_UNORM:
|
|
|
|
return 16;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkFormat DataFormatToVulkan(DataFormat format) {
|
|
|
|
switch (format) {
|
|
|
|
case DataFormat::D16: return VK_FORMAT_D16_UNORM;
|
|
|
|
case DataFormat::D32F: return VK_FORMAT_D32_SFLOAT;
|
|
|
|
case DataFormat::D32F_S8: return VK_FORMAT_D32_SFLOAT_S8_UINT;
|
|
|
|
case DataFormat::S8: return VK_FORMAT_S8_UINT;
|
|
|
|
case DataFormat::R16_FLOAT: return VK_FORMAT_R16_SFLOAT;
|
|
|
|
case DataFormat::R16G16_FLOAT: return VK_FORMAT_R16G16_SFLOAT;
|
|
|
|
case DataFormat::R16G16B16A16_FLOAT: return VK_FORMAT_R16G16B16A16_SFLOAT;
|
|
|
|
case DataFormat::R8_UNORM: return VK_FORMAT_R8_UNORM;
|
|
|
|
case DataFormat::R8G8_UNORM: return VK_FORMAT_R8G8_UNORM;
|
|
|
|
case DataFormat::R8G8B8_UNORM: return VK_FORMAT_R8G8B8_UNORM;
|
|
|
|
case DataFormat::R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
|
2017-01-21 13:11:03 +01:00
|
|
|
case DataFormat::R4G4_UNORM_PACK8: return VK_FORMAT_R4G4_UNORM_PACK8;
|
|
|
|
case DataFormat::R4G4B4A4_UNORM_PACK16: return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
|
|
|
case DataFormat::B4G4R4A4_UNORM_PACK16: return VK_FORMAT_B4G4R4A4_UNORM_PACK16;
|
|
|
|
case DataFormat::R5G5B5A1_UNORM_PACK16: return VK_FORMAT_R5G5B5A1_UNORM_PACK16;
|
|
|
|
case DataFormat::B5G5R5A1_UNORM_PACK16: return VK_FORMAT_B5G5R5A1_UNORM_PACK16;
|
|
|
|
case DataFormat::R5G6B5_UNORM_PACK16: return VK_FORMAT_R5G6B5_UNORM_PACK16;
|
|
|
|
case DataFormat::B5G6R5_UNORM_PACK16: return VK_FORMAT_B5G6R5_UNORM_PACK16;
|
|
|
|
case DataFormat::A1R5G5B5_UNORM_PACK16: return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
|
2016-12-26 13:22:48 +01:00
|
|
|
case DataFormat::R32_FLOAT: return VK_FORMAT_R32_SFLOAT;
|
|
|
|
case DataFormat::R32G32_FLOAT: return VK_FORMAT_R32G32_SFLOAT;
|
|
|
|
case DataFormat::R32G32B32_FLOAT: return VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
case DataFormat::R32G32B32A32_FLOAT: return VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
|
|
|
|
|
|
case DataFormat::BC1_RGBA_UNORM_BLOCK: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
|
|
|
|
case DataFormat::BC2_UNORM_BLOCK: return VK_FORMAT_BC2_UNORM_BLOCK;
|
|
|
|
case DataFormat::BC3_UNORM_BLOCK: return VK_FORMAT_BC3_UNORM_BLOCK;
|
|
|
|
case DataFormat::BC4_UNORM_BLOCK: return VK_FORMAT_BC4_UNORM_BLOCK;
|
|
|
|
case DataFormat::BC4_SNORM_BLOCK: return VK_FORMAT_BC4_SNORM_BLOCK;
|
|
|
|
case DataFormat::BC5_UNORM_BLOCK: return VK_FORMAT_BC5_UNORM_BLOCK;
|
|
|
|
case DataFormat::BC5_SNORM_BLOCK: return VK_FORMAT_BC5_SNORM_BLOCK;
|
|
|
|
case DataFormat::BC6H_SFLOAT_BLOCK: return VK_FORMAT_BC6H_SFLOAT_BLOCK;
|
|
|
|
case DataFormat::BC6H_UFLOAT_BLOCK: return VK_FORMAT_BC6H_UFLOAT_BLOCK;
|
|
|
|
case DataFormat::BC7_UNORM_BLOCK: return VK_FORMAT_BC7_UNORM_BLOCK;
|
|
|
|
case DataFormat::BC7_SRGB_BLOCK: return VK_FORMAT_BC7_SRGB_BLOCK;
|
|
|
|
default:
|
|
|
|
return VK_FORMAT_UNDEFINED;
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
inline VkSamplerAddressMode AddressModeToVulkan(Draw::TextureAddressMode mode) {
|
|
|
|
switch (mode) {
|
|
|
|
case TextureAddressMode::CLAMP_TO_BORDER: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
|
|
|
|
case TextureAddressMode::CLAMP_TO_EDGE: return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
|
|
|
case TextureAddressMode::REPEAT_MIRROR: return VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
|
|
|
|
default:
|
|
|
|
case TextureAddressMode::REPEAT: return VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class VKSamplerState : public SamplerState {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2016-12-25 21:21:56 +01:00
|
|
|
VKSamplerState(VulkanContext *vulkan, const SamplerStateDesc &desc) : vulkan_(vulkan) {
|
2015-10-10 16:41:19 +02:00
|
|
|
VkSamplerCreateInfo s = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
|
2016-12-25 21:21:56 +01:00
|
|
|
s.addressModeU = AddressModeToVulkan(desc.wrapU);
|
|
|
|
s.addressModeV = AddressModeToVulkan(desc.wrapV);
|
|
|
|
s.addressModeW = AddressModeToVulkan(desc.wrapW);
|
|
|
|
s.anisotropyEnable = desc.maxAniso > 1.0f;
|
|
|
|
s.magFilter = desc.magFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
|
|
|
s.minFilter = desc.minFilter == TextureFilter::LINEAR ? VK_FILTER_LINEAR : VK_FILTER_NEAREST;
|
|
|
|
s.mipmapMode = desc.mipFilter == TextureFilter::LINEAR ? VK_SAMPLER_MIPMAP_MODE_LINEAR : VK_SAMPLER_MIPMAP_MODE_NEAREST;
|
|
|
|
s.maxLod = desc.maxLod;
|
2016-01-03 12:37:05 +01:00
|
|
|
VkResult res = vkCreateSampler(vulkan_->GetDevice(), &s, nullptr, &sampler_);
|
2015-12-20 23:39:03 +01:00
|
|
|
assert(VK_SUCCESS == res);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
2016-12-25 21:21:56 +01:00
|
|
|
~VKSamplerState() {
|
2016-01-03 12:37:05 +01:00
|
|
|
vkDestroySampler(vulkan_->GetDevice(), sampler_, nullptr);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
VkSampler GetSampler() { return sampler_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
VulkanContext *vulkan_;
|
|
|
|
VkSampler sampler_;
|
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
SamplerState *VKContext::CreateSamplerState(const SamplerStateDesc &desc) {
|
|
|
|
return new VKSamplerState(vulkan_, desc);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 22:24:14 +01:00
|
|
|
RasterState *VKContext::CreateRasterState(const RasterStateDesc &desc) {
|
2016-12-25 21:21:56 +01:00
|
|
|
return new VKRasterState(vulkan_, desc);
|
2016-12-23 23:46:11 +01:00
|
|
|
}
|
|
|
|
|
2016-12-26 11:16:59 +01:00
|
|
|
void VKContext::BindSamplerStates(int start, int count, SamplerState **state) {
|
2015-10-10 16:41:19 +02:00
|
|
|
for (int i = start; i < start + count; i++) {
|
2016-12-25 21:21:56 +01:00
|
|
|
boundSamplers_[i] = (VKSamplerState *)state[i];
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enum class TextureState {
|
|
|
|
UNINITIALIZED,
|
|
|
|
STAGED,
|
|
|
|
INITIALIZED,
|
|
|
|
PENDING_DESTRUCTION,
|
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
class VKTexture : public Texture {
|
2015-10-10 16:41:19 +02:00
|
|
|
public:
|
2017-01-16 23:43:07 +07:00
|
|
|
VKTexture(VulkanContext *vulkan, const TextureDesc &desc)
|
|
|
|
: vulkan_(vulkan), format_(desc.format), mipLevels_(desc.mipLevels) {
|
|
|
|
Create(desc);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
~VKTexture() {
|
2015-10-10 16:41:19 +02:00
|
|
|
Destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) override;
|
|
|
|
|
2016-01-09 21:19:18 +01:00
|
|
|
VkImageView GetImageView() { return vkTex_->GetImageView(); }
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
private:
|
2017-01-16 23:43:07 +07:00
|
|
|
bool Create(const TextureDesc &desc) {
|
|
|
|
format_ = desc.format;
|
|
|
|
mipLevels_ = desc.mipLevels;
|
|
|
|
width_ = desc.width;
|
|
|
|
height_ = desc.height;
|
|
|
|
depth_ = desc.depth;
|
|
|
|
vkTex_ = new VulkanTexture(vulkan_);
|
2017-01-18 00:31:44 +07:00
|
|
|
if (desc.initData.size()) {
|
|
|
|
for (int i = 0; i < desc.initData.size(); i++) {
|
|
|
|
this->SetImageData(0, 0, 0, width_, height_, depth_, i, 0, desc.initData[i]);
|
|
|
|
}
|
|
|
|
}
|
2017-01-16 23:43:07 +07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-01-03 13:27:19 +01:00
|
|
|
void Destroy() {
|
2016-01-09 17:12:37 +01:00
|
|
|
if (vkTex_) {
|
2016-01-10 11:41:46 +01:00
|
|
|
vkTex_->Destroy();
|
2016-01-09 17:12:37 +01:00
|
|
|
delete vkTex_;
|
|
|
|
}
|
2016-01-03 13:27:19 +01:00
|
|
|
}
|
|
|
|
|
2015-12-31 01:07:06 +01:00
|
|
|
VulkanContext *vulkan_;
|
2016-01-03 12:37:05 +01:00
|
|
|
VulkanTexture *vkTex_;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
int mipLevels_;
|
|
|
|
|
2016-12-25 18:52:05 +01:00
|
|
|
DataFormat format_;
|
2015-10-10 16:41:19 +02:00
|
|
|
};
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
VKContext::VKContext(VulkanContext *vulkan)
|
2016-12-26 17:31:20 +01:00
|
|
|
: viewportDirty_(false), scissorDirty_(false), vulkan_(vulkan), frameNum_(0), caps_{} {
|
|
|
|
caps_.anisoSupported = vulkan->GetFeaturesAvailable().samplerAnisotropy != 0;
|
|
|
|
caps_.geometryShaderSupported = vulkan->GetFeaturesAvailable().geometryShader != 0;
|
|
|
|
caps_.tesselationShaderSupported = vulkan->GetFeaturesAvailable().tessellationShader != 0;
|
|
|
|
caps_.multiViewport = vulkan->GetFeaturesAvailable().multiViewport != 0;
|
|
|
|
caps_.dualSourceBlend = vulkan->GetFeaturesAvailable().dualSrcBlend != 0;
|
|
|
|
|
2015-12-31 01:07:06 +01:00
|
|
|
device_ = vulkan->GetDevice();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-01-02 02:08:05 +01:00
|
|
|
queue_ = vulkan->GetGraphicsQueue();
|
|
|
|
queueFamilyIndex_ = vulkan->GetGraphicsQueueFamilyIndex();
|
2016-12-26 11:06:17 +01:00
|
|
|
scissor_.offset.x = 0;
|
|
|
|
scissor_.offset.y = 0;
|
|
|
|
scissor_.extent.width = pixel_xres;
|
|
|
|
scissor_.extent.height = pixel_yres;
|
2016-01-02 02:08:05 +01:00
|
|
|
viewport_.x = 0;
|
|
|
|
viewport_.y = 0;
|
|
|
|
viewport_.width = pixel_xres;
|
|
|
|
viewport_.height = pixel_yres;
|
|
|
|
viewport_.minDepth = 0.0f;
|
|
|
|
viewport_.maxDepth = 0.0f;
|
2015-10-10 16:41:19 +02:00
|
|
|
memset(boundTextures_, 0, sizeof(boundTextures_));
|
|
|
|
CreatePresets();
|
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkCommandPoolCreateInfo p = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
|
2015-12-31 01:33:23 +01:00
|
|
|
p.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
2015-10-10 16:41:19 +02:00
|
|
|
p.queueFamilyIndex = vulkan->GetGraphicsQueueFamilyIndex();
|
|
|
|
VkResult res = vkCreateCommandPool(device_, &p, nullptr, &cmdPool_);
|
|
|
|
assert(VK_SUCCESS == res);
|
|
|
|
|
2016-01-02 02:08:05 +01:00
|
|
|
VkDescriptorPoolSize dpTypes[2];
|
2015-10-10 16:41:19 +02:00
|
|
|
dpTypes[0].descriptorCount = 200;
|
2016-01-03 12:37:05 +01:00
|
|
|
dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
|
|
|
dpTypes[1].descriptorCount = 200;
|
|
|
|
dpTypes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkDescriptorPoolCreateInfo dp = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
|
2016-01-03 13:27:19 +01:00
|
|
|
dp.flags = 0; // Don't want to mess around with individually freeing these, let's go dynamic each frame.
|
|
|
|
dp.maxSets = 200; // 200 textures per frame should be enough for the UI...
|
2015-10-10 16:41:19 +02:00
|
|
|
dp.pPoolSizes = dpTypes;
|
|
|
|
dp.poolSizeCount = ARRAY_SIZE(dpTypes);
|
2016-01-03 13:27:19 +01:00
|
|
|
res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[0].descriptorPool);
|
|
|
|
assert(VK_SUCCESS == res);
|
|
|
|
res = vkCreateDescriptorPool(device_, &dp, nullptr, &frame_[1].descriptorPool);
|
2015-10-10 16:41:19 +02:00
|
|
|
assert(VK_SUCCESS == res);
|
2016-01-03 12:37:05 +01:00
|
|
|
|
2016-01-03 18:31:03 +01:00
|
|
|
frame_[0].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024);
|
|
|
|
frame_[1].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-01-02 02:08:05 +01:00
|
|
|
// binding 0 - uniform data
|
2016-01-03 18:31:03 +01:00
|
|
|
// binding 1 - combined sampler/image
|
2016-01-02 02:08:05 +01:00
|
|
|
VkDescriptorSetLayoutBinding bindings[2];
|
2015-10-10 16:41:19 +02:00
|
|
|
bindings[0].descriptorCount = 1;
|
|
|
|
bindings[0].pImmutableSamplers = nullptr;
|
2016-01-02 02:08:05 +01:00
|
|
|
bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
2015-10-10 16:41:19 +02:00
|
|
|
bindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
2015-12-31 01:33:23 +01:00
|
|
|
bindings[0].binding = 0;
|
2015-10-10 16:41:19 +02:00
|
|
|
bindings[1].descriptorCount = 1;
|
|
|
|
bindings[1].pImmutableSamplers = nullptr;
|
2016-01-02 02:08:05 +01:00
|
|
|
bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
|
|
bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
2015-12-31 01:33:23 +01:00
|
|
|
bindings[1].binding = 1;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkDescriptorSetLayoutCreateInfo dsl = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
|
2016-01-02 02:08:05 +01:00
|
|
|
dsl.bindingCount = 2;
|
2015-10-10 16:41:19 +02:00
|
|
|
dsl.pBindings = bindings;
|
|
|
|
res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_);
|
|
|
|
assert(VK_SUCCESS == res);
|
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
|
2015-10-10 16:41:19 +02:00
|
|
|
pl.pPushConstantRanges = nullptr;
|
|
|
|
pl.pushConstantRangeCount = 0;
|
|
|
|
pl.setLayoutCount = 1;
|
|
|
|
pl.pSetLayouts = &descriptorSetLayout_;
|
|
|
|
res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_);
|
|
|
|
assert(VK_SUCCESS == res);
|
|
|
|
|
2016-01-03 18:31:03 +01:00
|
|
|
pipelineCache_ = vulkan_->CreatePipelineCache();
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
VKContext::~VKContext() {
|
2015-10-10 16:41:19 +02:00
|
|
|
vkDestroyCommandPool(device_, cmdPool_, nullptr);
|
|
|
|
// This also destroys all descriptor sets.
|
2016-01-03 13:27:19 +01:00
|
|
|
for (int i = 0; i < 2; i++) {
|
2016-01-10 14:24:10 +01:00
|
|
|
frame_[i].descSets_.clear();
|
2016-01-03 13:27:19 +01:00
|
|
|
vkDestroyDescriptorPool(device_, frame_[i].descriptorPool, nullptr);
|
2016-03-20 09:52:13 +01:00
|
|
|
frame_[i].pushBuffer->Destroy(vulkan_);
|
2016-01-10 14:24:10 +01:00
|
|
|
delete frame_[i].pushBuffer;
|
2016-01-03 13:27:19 +01:00
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
vkDestroyDescriptorSetLayout(device_, descriptorSetLayout_, nullptr);
|
|
|
|
vkDestroyPipelineLayout(device_, pipelineLayout_, nullptr);
|
|
|
|
vkDestroyPipelineCache(device_, pipelineCache_, nullptr);
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::Begin(bool clear, uint32_t colorval, float depthVal, int stencilVal) {
|
2016-01-02 02:08:05 +01:00
|
|
|
VkClearValue clearVal[2] = {};
|
2015-10-10 16:41:19 +02:00
|
|
|
Uint8x4ToFloat4(colorval, clearVal[0].color.float32);
|
2016-01-02 02:08:05 +01:00
|
|
|
|
2016-03-13 17:05:03 +01:00
|
|
|
// // Debug flicker - used to see if we swap at all. no longer necessary
|
|
|
|
// if (frameNum_ & 1)
|
|
|
|
// clearVal[0].color.float32[2] = 1.0f;
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
clearVal[1].depthStencil.depth = depthVal;
|
|
|
|
clearVal[1].depthStencil.stencil = stencilVal;
|
|
|
|
|
2016-01-02 02:08:05 +01:00
|
|
|
cmd_ = vulkan_->BeginSurfaceRenderPass(clearVal);
|
|
|
|
|
2016-01-03 13:27:19 +01:00
|
|
|
FrameData *frame = &frame_[frameNum_ & 1];
|
|
|
|
push_ = frame->pushBuffer;
|
2016-01-02 02:08:05 +01:00
|
|
|
|
|
|
|
// OK, we now know that nothing is reading from this frame's data pushbuffer,
|
2016-03-20 09:52:13 +01:00
|
|
|
push_->Reset();
|
2016-03-20 15:36:22 -07:00
|
|
|
push_->Begin(vulkan_);
|
2016-01-03 13:27:19 +01:00
|
|
|
|
|
|
|
frame->descSets_.clear();
|
|
|
|
VkResult result = vkResetDescriptorPool(device_, frame->descriptorPool, 0);
|
|
|
|
assert(result == VK_SUCCESS);
|
|
|
|
|
2016-12-26 11:06:17 +01:00
|
|
|
scissor_.extent.width = pixel_xres;
|
|
|
|
scissor_.extent.height = pixel_yres;
|
2016-01-02 02:08:05 +01:00
|
|
|
scissorDirty_ = true;
|
|
|
|
viewportDirty_ = true;
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::End() {
|
2016-01-03 12:37:05 +01:00
|
|
|
// Stop collecting data in the frame's data pushbuffer.
|
2016-03-20 15:36:22 -07:00
|
|
|
push_->End();
|
2016-01-02 02:08:05 +01:00
|
|
|
vulkan_->EndSurfaceRenderPass();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
frameNum_++;
|
2016-01-02 02:08:05 +01:00
|
|
|
cmd_ = nullptr; // will be set on the next begin
|
|
|
|
push_ = nullptr;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
DirtyDynamicState();
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
VkDescriptorSet VKContext::GetOrCreateDescriptorSet(VkBuffer buf) {
|
2015-10-10 16:41:19 +02:00
|
|
|
DescriptorSetKey key;
|
2016-01-03 13:27:19 +01:00
|
|
|
|
|
|
|
FrameData *frame = &frame_[frameNum_ & 1];
|
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
key.texture_ = boundTextures_[0];
|
|
|
|
key.sampler_ = boundSamplers_[0];
|
2016-03-20 09:52:13 +01:00
|
|
|
key.buffer_ = buf;
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-01-03 13:27:19 +01:00
|
|
|
auto iter = frame->descSets_.find(key);
|
|
|
|
if (iter != frame->descSets_.end()) {
|
2015-10-10 16:41:19 +02:00
|
|
|
return iter->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDescriptorSet descSet;
|
2016-03-21 00:35:27 -07:00
|
|
|
VkDescriptorSetAllocateInfo alloc = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
|
2016-01-03 13:27:19 +01:00
|
|
|
alloc.descriptorPool = frame->descriptorPool;
|
2015-10-10 16:41:19 +02:00
|
|
|
alloc.pSetLayouts = &descriptorSetLayout_;
|
|
|
|
alloc.descriptorSetCount = 1;
|
|
|
|
VkResult res = vkAllocateDescriptorSets(device_, &alloc, &descSet);
|
|
|
|
assert(VK_SUCCESS == res);
|
2015-12-20 23:39:03 +01:00
|
|
|
|
2015-10-10 16:41:19 +02:00
|
|
|
VkDescriptorBufferInfo bufferDesc;
|
2016-03-20 09:52:13 +01:00
|
|
|
bufferDesc.buffer = buf;
|
2015-10-10 16:41:19 +02:00
|
|
|
bufferDesc.offset = 0;
|
2016-12-26 11:06:17 +01:00
|
|
|
bufferDesc.range = curPipeline_->GetUBOSize();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
VkDescriptorImageInfo imageDesc;
|
|
|
|
imageDesc.imageView = boundTextures_[0]->GetImageView();
|
|
|
|
imageDesc.sampler = boundSamplers_[0]->GetSampler();
|
|
|
|
imageDesc.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
|
|
|
|
2016-03-21 00:35:27 -07:00
|
|
|
VkWriteDescriptorSet writes[2] = {};
|
2015-10-10 16:41:19 +02:00
|
|
|
writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
|
|
writes[0].dstSet = descSet;
|
|
|
|
writes[0].dstArrayElement = 0;
|
2016-01-02 02:08:05 +01:00
|
|
|
writes[0].dstBinding = 0;
|
2015-10-10 16:41:19 +02:00
|
|
|
writes[0].pBufferInfo = &bufferDesc;
|
2016-01-03 00:46:41 +01:00
|
|
|
writes[0].pImageInfo = nullptr;
|
|
|
|
writes[0].pTexelBufferView = nullptr;
|
2015-10-10 16:41:19 +02:00
|
|
|
writes[0].descriptorCount = 1;
|
|
|
|
writes[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
|
|
|
|
|
|
|
writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
|
|
|
writes[1].dstSet = descSet;
|
|
|
|
writes[1].dstArrayElement = 0;
|
2016-01-02 02:08:05 +01:00
|
|
|
writes[1].dstBinding = 1;
|
2016-01-03 00:46:41 +01:00
|
|
|
writes[1].pBufferInfo = nullptr;
|
2015-10-10 16:41:19 +02:00
|
|
|
writes[1].pImageInfo = &imageDesc;
|
2016-01-03 00:46:41 +01:00
|
|
|
writes[1].pTexelBufferView = nullptr;
|
2015-10-10 16:41:19 +02:00
|
|
|
writes[1].descriptorCount = 1;
|
|
|
|
writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
|
|
|
|
|
|
|
vkUpdateDescriptorSets(device_, 2, writes, 0, nullptr);
|
|
|
|
|
2016-01-03 13:27:19 +01:00
|
|
|
frame->descSets_[key] = descSet;
|
2015-10-10 16:41:19 +02:00
|
|
|
return descSet;
|
|
|
|
}
|
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
|
|
|
|
VKPipeline *pipeline = new VKPipeline();
|
|
|
|
VKInputLayout *input = (VKInputLayout *)desc.inputLayout;
|
|
|
|
VKBlendState *blend = (VKBlendState *)desc.blend;
|
|
|
|
VKDepthStencilState *depth = (VKDepthStencilState *)desc.depthStencil;
|
|
|
|
VKRasterState *raster = (VKRasterState *)desc.raster;
|
|
|
|
for (int i = 0; i < input->bindings.size(); i++) {
|
|
|
|
pipeline->stride[i] = input->bindings[i].stride;
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 23:03:20 +01:00
|
|
|
std::vector<VkPipelineShaderStageCreateInfo> stages;
|
2016-12-26 17:03:01 +01:00
|
|
|
stages.resize(desc.shaders.size());
|
2016-12-25 23:03:20 +01:00
|
|
|
int i = 0;
|
2016-12-26 17:03:01 +01:00
|
|
|
for (auto &iter : desc.shaders) {
|
|
|
|
VKShaderModule *vkshader = (VKShaderModule *)iter;
|
2016-12-25 23:03:20 +01:00
|
|
|
VkPipelineShaderStageCreateInfo &stage = stages[i++];
|
|
|
|
stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
|
|
stage.pNext = nullptr;
|
|
|
|
stage.pSpecializationInfo = nullptr;
|
2016-12-26 17:03:01 +01:00
|
|
|
stage.stage = StageToVulkan(vkshader->GetStage());
|
|
|
|
stage.module = vkshader->Get();
|
2016-12-25 23:03:20 +01:00
|
|
|
stage.pName = "main";
|
|
|
|
stage.flags = 0;
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkPipelineInputAssemblyStateCreateInfo inputAssembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
|
2016-12-26 17:03:01 +01:00
|
|
|
inputAssembly.topology = primToVK[(int)desc.prim];
|
2015-10-10 16:41:19 +02:00
|
|
|
inputAssembly.primitiveRestartEnable = false;
|
|
|
|
|
|
|
|
VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
2016-04-02 23:57:23 +02:00
|
|
|
VkPipelineDynamicStateCreateInfo dynamicInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
2015-10-10 16:41:19 +02:00
|
|
|
dynamicInfo.dynamicStateCount = ARRAY_SIZE(dynamics);
|
|
|
|
dynamicInfo.pDynamicStates = dynamics;
|
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
|
2015-10-10 16:41:19 +02:00
|
|
|
ms.pNext = nullptr;
|
|
|
|
ms.pSampleMask = nullptr;
|
|
|
|
ms.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkPipelineViewportStateCreateInfo vs = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
|
2015-10-10 16:41:19 +02:00
|
|
|
vs.pNext = nullptr;
|
|
|
|
vs.viewportCount = 1;
|
|
|
|
vs.scissorCount = 1;
|
|
|
|
vs.pViewports = nullptr; // dynamic
|
|
|
|
vs.pScissors = nullptr; // dynamic
|
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
|
|
|
raster->ToVulkan(&rs);
|
|
|
|
|
2016-04-02 23:57:23 +02:00
|
|
|
VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
|
2015-10-10 16:41:19 +02:00
|
|
|
info.pNext = nullptr;
|
|
|
|
info.flags = 0;
|
2016-12-25 23:03:20 +01:00
|
|
|
info.stageCount = (uint32_t)stages.size();
|
|
|
|
info.pStages = stages.data();
|
2016-12-26 18:32:52 +01:00
|
|
|
info.pColorBlendState = &blend->info;
|
2016-12-26 23:11:31 +01:00
|
|
|
info.pDepthStencilState = &depth->info;
|
2015-10-10 16:41:19 +02:00
|
|
|
info.pDynamicState = &dynamicInfo;
|
|
|
|
info.pInputAssemblyState = &inputAssembly;
|
|
|
|
info.pTessellationState = nullptr;
|
|
|
|
info.pMultisampleState = &ms;
|
2016-12-26 17:03:01 +01:00
|
|
|
info.pVertexInputState = &input->visc;
|
|
|
|
info.pRasterizationState = &rs;
|
2015-10-10 16:41:19 +02:00
|
|
|
info.pViewportState = &vs; // Must set viewport and scissor counts even if we set the actual state dynamically.
|
|
|
|
info.layout = pipelineLayout_;
|
|
|
|
info.subpass = 0;
|
2016-01-02 02:08:05 +01:00
|
|
|
info.renderPass = vulkan_->GetSurfaceRenderPass();
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
// OK, need to create a new pipeline.
|
2016-12-26 17:03:01 +01:00
|
|
|
VkResult result = vkCreateGraphicsPipelines(device_, pipelineCache_, 1, &info, nullptr, &pipeline->vkpipeline);
|
2015-10-10 16:41:19 +02:00
|
|
|
if (result != VK_SUCCESS) {
|
|
|
|
ELOG("Failed to create graphics pipeline");
|
2016-12-26 17:03:01 +01:00
|
|
|
delete pipeline;
|
|
|
|
return nullptr;
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
return pipeline;
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::SetScissorRect(int left, int top, int width, int height) {
|
2015-10-10 16:41:19 +02:00
|
|
|
scissor_.offset.x = left;
|
|
|
|
scissor_.offset.y = top;
|
|
|
|
scissor_.extent.width = width;
|
|
|
|
scissor_.extent.height = height;
|
|
|
|
scissorDirty_ = true;
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::SetViewports(int count, Viewport *viewports) {
|
2015-10-10 16:41:19 +02:00
|
|
|
viewport_.x = viewports[0].TopLeftX;
|
|
|
|
viewport_.y = viewports[0].TopLeftY;
|
|
|
|
viewport_.width = viewports[0].Width;
|
|
|
|
viewport_.height = viewports[0].Height;
|
|
|
|
viewport_.minDepth = viewports[0].MinDepth;
|
|
|
|
viewport_.maxDepth = viewports[0].MaxDepth;
|
|
|
|
viewportDirty_ = true;
|
|
|
|
}
|
|
|
|
|
2016-12-27 15:52:03 +01:00
|
|
|
void VKContext::SetBlendFactor(float color[4]) {
|
|
|
|
vkCmdSetBlendConstants(cmd_, color);
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::ApplyDynamicState() {
|
2015-10-10 16:41:19 +02:00
|
|
|
if (scissorDirty_) {
|
2016-12-26 11:06:17 +01:00
|
|
|
vkCmdSetScissor(cmd_, 0, 1, &scissor_);
|
2015-10-10 16:41:19 +02:00
|
|
|
scissorDirty_ = false;
|
|
|
|
}
|
|
|
|
if (viewportDirty_) {
|
|
|
|
vkCmdSetViewport(cmd_, 0, 1, &viewport_);
|
|
|
|
viewportDirty_ = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::DirtyDynamicState() {
|
2015-10-10 16:41:19 +02:00
|
|
|
scissorDirty_ = true;
|
|
|
|
viewportDirty_ = true;
|
|
|
|
}
|
|
|
|
|
2016-12-26 13:22:48 +01:00
|
|
|
InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
|
|
|
|
VKInputLayout *vl = new VKInputLayout();
|
|
|
|
vl->visc = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
|
|
|
|
vl->visc.flags = 0;
|
|
|
|
vl->visc.vertexAttributeDescriptionCount = (uint32_t)desc.attributes.size();
|
|
|
|
vl->visc.vertexBindingDescriptionCount = (uint32_t)desc.bindings.size();
|
|
|
|
vl->bindings.resize(vl->visc.vertexBindingDescriptionCount);
|
|
|
|
vl->attributes.resize(vl->visc.vertexAttributeDescriptionCount);
|
|
|
|
vl->visc.pVertexBindingDescriptions = vl->bindings.data();
|
|
|
|
vl->visc.pVertexAttributeDescriptions = vl->attributes.data();
|
|
|
|
for (size_t i = 0; i < desc.attributes.size(); i++) {
|
|
|
|
vl->attributes[i].binding = (uint32_t)desc.attributes[i].binding;
|
|
|
|
vl->attributes[i].format = DataFormatToVulkan(desc.attributes[i].format);
|
|
|
|
vl->attributes[i].location = desc.attributes[i].location;
|
|
|
|
vl->attributes[i].offset = desc.attributes[i].offset;
|
|
|
|
}
|
|
|
|
for (size_t i = 0; i < desc.bindings.size(); i++) {
|
|
|
|
vl->bindings[i].inputRate = desc.bindings[i].instanceRate ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
|
|
|
vl->bindings[i].binding = (uint32_t)i;
|
|
|
|
vl->bindings[i].stride = desc.bindings[i].stride;
|
|
|
|
}
|
|
|
|
return vl;
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2017-01-16 23:43:07 +07:00
|
|
|
Texture *VKContext::CreateTexture(const TextureDesc &desc) {
|
|
|
|
return new VKTexture(vulkan_, desc);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKTexture::SetImageData(int x, int y, int z, int width, int height, int depth, int level, int stride, const uint8_t *data) {
|
2016-12-26 13:22:48 +01:00
|
|
|
VkFormat vulkanFormat = DataFormatToVulkan(format_);
|
2017-01-18 00:31:44 +07:00
|
|
|
if (stride == 0) {
|
2017-01-21 13:11:03 +01:00
|
|
|
stride = width * (int)DataFormatSizeInBytes(format_);
|
2017-01-18 00:31:44 +07:00
|
|
|
}
|
2016-12-26 13:22:48 +01:00
|
|
|
int bpp = GetBpp(vulkanFormat);
|
2016-01-03 12:37:05 +01:00
|
|
|
int bytesPerPixel = bpp / 8;
|
2016-01-10 11:41:46 +01:00
|
|
|
vkTex_->Create(width, height, vulkanFormat);
|
2016-01-03 12:37:05 +01:00
|
|
|
int rowPitch;
|
2016-01-10 11:41:46 +01:00
|
|
|
uint8_t *dstData = vkTex_->Lock(0, &rowPitch);
|
2016-01-03 12:37:05 +01:00
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
memcpy(dstData + rowPitch * y, data + stride * y, width * bytesPerPixel);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
2016-01-10 11:41:46 +01:00
|
|
|
vkTex_->Unlock();
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-26 23:11:31 +01:00
|
|
|
inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {
|
|
|
|
dest.compareMask = src.compareMask;
|
|
|
|
dest.reference = src.reference;
|
|
|
|
dest.writeMask = src.writeMask;
|
|
|
|
dest.compareOp = compToVK[(int)src.compareOp];
|
|
|
|
dest.failOp = stencilOpToVK[(int)src.failOp];
|
|
|
|
dest.passOp = stencilOpToVK[(int)src.passOp];
|
|
|
|
dest.depthFailOp = stencilOpToVK[(int)src.depthFailOp];
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
DepthStencilState *VKContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
|
|
|
|
VKDepthStencilState *ds = new VKDepthStencilState();
|
2016-12-26 23:11:31 +01:00
|
|
|
ds->info.depthCompareOp = compToVK[(int)desc.depthCompare];
|
|
|
|
ds->info.depthTestEnable = desc.depthTestEnabled;
|
|
|
|
ds->info.depthWriteEnable = desc.depthWriteEnabled;
|
|
|
|
ds->info.stencilTestEnable = false;
|
|
|
|
ds->info.depthBoundsTestEnable = false;
|
|
|
|
if (ds->info.stencilTestEnable) {
|
|
|
|
CopySide(ds->info.front, desc.front);
|
|
|
|
CopySide(ds->info.back, desc.back);
|
|
|
|
}
|
2015-10-10 16:41:19 +02:00
|
|
|
return ds;
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
BlendState *VKContext::CreateBlendState(const BlendStateDesc &desc) {
|
|
|
|
VKBlendState *bs = new VKBlendState();
|
2016-12-26 18:32:52 +01:00
|
|
|
bs->info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
|
|
bs->info.attachmentCount = 1;
|
|
|
|
bs->info.logicOp = logicOpToVK[(int)desc.logicOp];
|
|
|
|
bs->info.logicOpEnable = desc.logicEnabled;
|
|
|
|
bs->attachments.resize(1);
|
|
|
|
bs->attachments[0].blendEnable = desc.enabled;
|
|
|
|
bs->attachments[0].colorBlendOp = blendEqToVk[(int)desc.eqCol];
|
|
|
|
bs->attachments[0].alphaBlendOp = blendEqToVk[(int)desc.eqAlpha];
|
|
|
|
bs->attachments[0].colorWriteMask = desc.colorMask;
|
|
|
|
bs->attachments[0].dstAlphaBlendFactor = blendFactorToVk[(int)desc.dstAlpha];
|
|
|
|
bs->attachments[0].dstColorBlendFactor = blendFactorToVk[(int)desc.dstCol];
|
|
|
|
bs->attachments[0].srcAlphaBlendFactor = blendFactorToVk[(int)desc.srcAlpha];
|
|
|
|
bs->attachments[0].srcColorBlendFactor = blendFactorToVk[(int)desc.srcCol];
|
|
|
|
bs->info.pAttachments = bs->attachments.data();
|
2015-10-10 16:41:19 +02:00
|
|
|
return bs;
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
Buffer *VKContext::CreateBuffer(size_t size, uint32_t usageFlags) {
|
2017-01-17 23:14:47 +07:00
|
|
|
return new VKBuffer(size, usageFlags);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::BindTextures(int start, int count, Texture **textures) {
|
2015-10-10 16:41:19 +02:00
|
|
|
for (int i = start; i < start + count; i++) {
|
2016-12-25 21:21:56 +01:00
|
|
|
boundTextures_[i] = static_cast<VKTexture *>(textures[i]);
|
2015-10-10 16:41:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-27 17:38:26 +01:00
|
|
|
ShaderModule *VKContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t size) {
|
2016-12-25 22:24:14 +01:00
|
|
|
VKShaderModule *shader = new VKShaderModule(stage);
|
2016-12-27 17:38:26 +01:00
|
|
|
if (shader->Compile(vulkan_, language, data, size)) {
|
2015-10-10 16:41:19 +02:00
|
|
|
return shader;
|
|
|
|
} else {
|
2016-12-27 17:38:26 +01:00
|
|
|
ELOG("Failed to compile shader: %s", (const char *)data);
|
2015-10-10 16:41:19 +02:00
|
|
|
shader->Release();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-26 11:06:17 +01:00
|
|
|
int VKPipeline::GetUniformLoc(const char *name) {
|
2015-10-10 16:41:19 +02:00
|
|
|
int loc = -1;
|
|
|
|
|
|
|
|
// HACK! As we only use one uniform we hardcode it.
|
|
|
|
if (!strcmp(name, "WorldViewProj")) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return loc;
|
|
|
|
}
|
|
|
|
|
2016-12-26 11:06:17 +01:00
|
|
|
void VKPipeline::SetVector(const char *name, float *value, int n) {
|
2015-10-10 16:41:19 +02:00
|
|
|
// TODO: Implement
|
|
|
|
}
|
|
|
|
|
2016-12-26 11:06:17 +01:00
|
|
|
void VKPipeline::SetMatrix4x4(const char *name, const float value[16]) {
|
2015-10-10 16:41:19 +02:00
|
|
|
int loc = GetUniformLoc(name);
|
|
|
|
if (loc != -1) {
|
|
|
|
memcpy(ubo_ + loc, value, 16 * sizeof(float));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-25 18:52:05 +01:00
|
|
|
inline VkPrimitiveTopology PrimToVK(Primitive prim) {
|
|
|
|
switch (prim) {
|
|
|
|
case Primitive::POINT_LIST: return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
|
|
|
case Primitive::LINE_LIST: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
|
|
|
case Primitive::LINE_LIST_ADJ: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
|
|
|
|
case Primitive::LINE_STRIP: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
|
|
|
case Primitive::LINE_STRIP_ADJ: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
|
|
|
|
case Primitive::TRIANGLE_LIST: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
case Primitive::TRIANGLE_LIST_ADJ: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
|
|
|
|
case Primitive::TRIANGLE_STRIP: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
|
|
|
case Primitive::TRIANGLE_STRIP_ADJ: return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
|
|
|
|
case Primitive::TRIANGLE_FAN: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
|
|
|
case Primitive::PATCH_LIST: return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
|
|
|
default:
|
|
|
|
return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 23:14:47 +07:00
|
|
|
void VKContext::Draw(int vertexCount, int offset) {
|
2015-10-10 16:41:19 +02:00
|
|
|
ApplyDynamicState();
|
|
|
|
|
2017-01-17 23:14:47 +07:00
|
|
|
VKBuffer *vbuf = curVBuffers_[0];
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer vulkanVbuf;
|
|
|
|
VkBuffer vulkanUBObuf;
|
2016-12-26 11:06:17 +01:00
|
|
|
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
|
2016-03-21 00:35:27 -07:00
|
|
|
size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), &vulkanVbuf);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, curPipeline_->vkpipeline);
|
2016-03-20 09:52:13 +01:00
|
|
|
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
|
2015-10-10 16:41:19 +02:00
|
|
|
vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer buffers[1] = { vulkanVbuf };
|
2015-10-10 16:41:19 +02:00
|
|
|
VkDeviceSize offsets[1] = { vbBindOffset };
|
|
|
|
vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
|
|
|
|
vkCmdDraw(cmd_, vertexCount, 1, offset, 0);
|
|
|
|
}
|
|
|
|
|
2017-01-17 23:14:47 +07:00
|
|
|
void VKContext::DrawIndexed(int vertexCount, int offset) {
|
2015-10-10 16:41:19 +02:00
|
|
|
ApplyDynamicState();
|
|
|
|
|
2017-01-17 23:14:47 +07:00
|
|
|
VKBuffer *ibuf = static_cast<VKBuffer *>(curIBuffer_);
|
|
|
|
VKBuffer *vbuf = static_cast<VKBuffer *>(curVBuffers_[0]);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
|
2016-12-26 11:06:17 +01:00
|
|
|
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
|
2016-03-20 09:52:13 +01:00
|
|
|
size_t vbBindOffset = push_->Push(vbuf->GetData(), vbuf->GetSize(), &vulkanVbuf);
|
|
|
|
size_t ibBindOffset = push_->Push(ibuf->GetData(), ibuf->GetSize(), &vulkanIbuf);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, curPipeline_->vkpipeline);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
|
2015-10-10 16:41:19 +02:00
|
|
|
vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
|
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer buffers[1] = { vulkanVbuf };
|
2015-10-10 16:41:19 +02:00
|
|
|
VkDeviceSize offsets[1] = { vbBindOffset };
|
|
|
|
vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
|
|
|
|
|
2016-03-21 06:57:03 -07:00
|
|
|
vkCmdBindIndexBuffer(cmd_, vulkanIbuf, ibBindOffset, VK_INDEX_TYPE_UINT32);
|
2015-10-10 16:41:19 +02:00
|
|
|
vkCmdDrawIndexed(cmd_, vertexCount, 1, 0, offset, 0);
|
|
|
|
}
|
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
void VKContext::DrawUP(const void *vdata, int vertexCount) {
|
2015-10-10 16:41:19 +02:00
|
|
|
ApplyDynamicState();
|
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer vulkanVbuf, vulkanUBObuf;
|
2016-12-26 17:03:01 +01:00
|
|
|
size_t vbBindOffset = push_->Push(vdata, vertexCount * curPipeline_->stride[0], &vulkanVbuf);
|
2016-12-26 11:06:17 +01:00
|
|
|
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-12-26 17:03:01 +01:00
|
|
|
vkCmdBindPipeline(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, curPipeline_->vkpipeline);
|
2015-10-10 16:41:19 +02:00
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkBuffer buffers[1] = { vulkanVbuf };
|
2015-10-10 16:41:19 +02:00
|
|
|
VkDeviceSize offsets[1] = { vbBindOffset };
|
|
|
|
vkCmdBindVertexBuffers(cmd_, 0, 1, buffers, offsets);
|
2016-01-03 12:37:05 +01:00
|
|
|
|
2016-03-20 09:52:13 +01:00
|
|
|
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
|
2016-01-03 12:37:05 +01:00
|
|
|
vkCmdBindDescriptorSets(cmd_, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descSet, 1, &ubo_offset);
|
2015-10-10 16:41:19 +02:00
|
|
|
vkCmdDraw(cmd_, vertexCount, 1, 0, 0);
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:21:56 +01:00
|
|
|
void VKContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) {
|
2016-12-25 18:52:05 +01:00
|
|
|
if (mask & ClearFlag::COLOR) {
|
2015-10-10 16:41:19 +02:00
|
|
|
VkClearColorValue col;
|
|
|
|
Uint8x4ToFloat4(colorval, col.float32);
|
|
|
|
|
|
|
|
/*
|
|
|
|
VkRect3D rect;
|
|
|
|
rect.extent.width =
|
|
|
|
vkCmdClearColorAttachment(cmdBuf_, 0, imageLayout_, &col, 1, nullptr);
|
|
|
|
*/
|
|
|
|
}
|
2016-12-25 18:52:05 +01:00
|
|
|
if (mask & (ClearFlag::DEPTH | ClearFlag::STENCIL)) {
|
2015-10-10 16:41:19 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-25 21:01:57 +01:00
|
|
|
DrawContext *T3DCreateVulkanContext(VulkanContext *vulkan) {
|
2016-12-25 21:21:56 +01:00
|
|
|
return new VKContext(vulkan);
|
2016-01-06 12:52:08 +01:00
|
|
|
}
|
2016-01-03 14:00:05 +01:00
|
|
|
|
|
|
|
void AddFeature(std::vector<std::string> &features, const char *name, VkBool32 available, VkBool32 enabled) {
|
|
|
|
char buf[512];
|
|
|
|
snprintf(buf, sizeof(buf), "%s: Available: %d Enabled: %d", name, (int)available, (int)enabled);
|
|
|
|
features.push_back(buf);
|
|
|
|
}
|
|
|
|
|
2016-12-26 17:31:20 +01:00
|
|
|
std::vector<std::string> VKContext::GetFeatureList() const {
|
2016-01-03 14:00:05 +01:00
|
|
|
const VkPhysicalDeviceFeatures &available = vulkan_->GetFeaturesAvailable();
|
|
|
|
const VkPhysicalDeviceFeatures &enabled = vulkan_->GetFeaturesEnabled();
|
2016-12-26 17:31:20 +01:00
|
|
|
|
2016-01-03 14:00:05 +01:00
|
|
|
std::vector<std::string> features;
|
|
|
|
AddFeature(features, "dualSrcBlend", available.dualSrcBlend, enabled.dualSrcBlend);
|
|
|
|
AddFeature(features, "logicOp", available.logicOp, enabled.logicOp);
|
|
|
|
AddFeature(features, "geometryShader", available.geometryShader, enabled.geometryShader);
|
|
|
|
AddFeature(features, "depthBounds", available.depthBounds, enabled.depthBounds);
|
|
|
|
AddFeature(features, "depthClamp", available.depthClamp, enabled.depthClamp);
|
|
|
|
AddFeature(features, "fillModeNonSolid", available.fillModeNonSolid, enabled.fillModeNonSolid);
|
|
|
|
AddFeature(features, "largePoints", available.largePoints, enabled.largePoints);
|
|
|
|
AddFeature(features, "wideLines", available.wideLines, enabled.wideLines);
|
|
|
|
AddFeature(features, "pipelineStatisticsQuery", available.pipelineStatisticsQuery, enabled.pipelineStatisticsQuery);
|
|
|
|
AddFeature(features, "samplerAnisotropy", available.samplerAnisotropy, enabled.samplerAnisotropy);
|
|
|
|
AddFeature(features, "textureCompressionBC", available.textureCompressionBC, enabled.textureCompressionBC);
|
|
|
|
AddFeature(features, "textureCompressionETC2", available.textureCompressionETC2, enabled.textureCompressionETC2);
|
|
|
|
AddFeature(features, "textureCompressionASTC_LDR", available.textureCompressionASTC_LDR, enabled.textureCompressionASTC_LDR);
|
|
|
|
AddFeature(features, "shaderClipDistance", available.shaderClipDistance, enabled.shaderClipDistance);
|
|
|
|
AddFeature(features, "shaderCullDistance", available.shaderCullDistance, enabled.shaderCullDistance);
|
2016-01-19 18:41:45 +01:00
|
|
|
AddFeature(features, "occlusionQueryPrecise", available.occlusionQueryPrecise, enabled.occlusionQueryPrecise);
|
|
|
|
AddFeature(features, "multiDrawIndirect", available.multiDrawIndirect, enabled.multiDrawIndirect);
|
2016-01-10 12:27:45 +01:00
|
|
|
|
|
|
|
// Also list texture formats and their properties.
|
|
|
|
for (int i = VK_FORMAT_BEGIN_RANGE; i <= VK_FORMAT_END_RANGE; i++) {
|
|
|
|
// TODO
|
|
|
|
}
|
|
|
|
|
2016-01-03 14:00:05 +01:00
|
|
|
return features;
|
|
|
|
}
|
2016-12-25 18:18:19 +01:00
|
|
|
|
2017-01-19 12:16:36 +07:00
|
|
|
uint32_t VKContext::GetDataFormatSupport(DataFormat fmt) const {
|
|
|
|
// TODO: Actually do proper checks
|
|
|
|
switch (fmt) {
|
|
|
|
case DataFormat::B8G8R8A8_UNORM:
|
|
|
|
return FMT_RENDERTARGET | FMT_TEXTURE;
|
2017-01-21 13:11:03 +01:00
|
|
|
case DataFormat::B4G4R4A4_UNORM_PACK16:
|
|
|
|
// This is the one that's guaranteed to be supported.
|
|
|
|
// A four-component, 16-bit packed unsigned normalized format that has a 4-bit B component in bits 12..15, a 4-bit
|
|
|
|
// G component in bits 8..11, a 4 - bit R component in bits 4..7, and a 4 - bit A component in bits 0..3
|
|
|
|
return FMT_RENDERTARGET | FMT_TEXTURE;
|
|
|
|
case DataFormat::R4G4B4A4_UNORM_PACK16:
|
|
|
|
return 0;
|
|
|
|
case DataFormat::A4B4G4R4_UNORM_PACK16:
|
2017-01-19 12:16:36 +07:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
case DataFormat::R8G8B8A8_UNORM:
|
|
|
|
return FMT_RENDERTARGET | FMT_TEXTURE | FMT_INPUTLAYOUT;
|
|
|
|
|
|
|
|
case DataFormat::R32_FLOAT:
|
|
|
|
case DataFormat::R32G32_FLOAT:
|
|
|
|
case DataFormat::R32G32B32_FLOAT:
|
|
|
|
case DataFormat::R32G32B32A32_FLOAT:
|
|
|
|
return FMT_INPUTLAYOUT;
|
|
|
|
|
|
|
|
case DataFormat::R8_UNORM:
|
2017-01-21 13:11:03 +01:00
|
|
|
return FMT_TEXTURE;
|
|
|
|
|
2017-01-19 12:16:36 +07:00
|
|
|
case DataFormat::BC1_RGBA_UNORM_BLOCK:
|
|
|
|
case DataFormat::BC2_UNORM_BLOCK:
|
|
|
|
case DataFormat::BC3_UNORM_BLOCK:
|
|
|
|
return FMT_TEXTURE;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-25 18:18:19 +01:00
|
|
|
} // namespace Draw
|