2022-10-03 22:49:19 -04:00
|
|
|
#include <time.h>
|
|
|
|
#include <errno.h>
|
2022-10-04 09:34:57 -04:00
|
|
|
#include <vulkan/vulkan.h>
|
|
|
|
#include <vector>
|
|
|
|
#include <cstring>
|
|
|
|
#include <cstdio>
|
2022-10-04 09:53:38 -04:00
|
|
|
#include <array>
|
2022-10-04 10:01:45 -04:00
|
|
|
#include <limits>
|
2022-10-04 10:20:38 -04:00
|
|
|
#include <fstream>
|
2022-10-05 09:44:17 -04:00
|
|
|
#include <glslang/Public/ShaderLang.h>
|
|
|
|
#include <glslang/SPIRV/GlslangToSpv.h>
|
2022-10-03 22:49:19 -04:00
|
|
|
|
|
|
|
#include "gfx_rendering_api.h"
|
2022-10-04 09:53:38 -04:00
|
|
|
#include "gfx_pc.h"
|
|
|
|
#include "gfx_window_manager_api.h"
|
2022-10-04 10:34:29 -04:00
|
|
|
#include "gfx_cc.h"
|
2022-10-05 09:44:17 -04:00
|
|
|
#include "defaultresources.hpp"
|
2022-10-04 09:53:38 -04:00
|
|
|
|
|
|
|
static VkInstance instance = VK_NULL_HANDLE;
|
|
|
|
static VkPhysicalDevice physical_device = VK_NULL_HANDLE;
|
|
|
|
static VkDevice device = VK_NULL_HANDLE;
|
|
|
|
static VkQueue graphics_queue = VK_NULL_HANDLE;
|
|
|
|
static VkQueue present_queue = VK_NULL_HANDLE;
|
|
|
|
static VkCommandPool command_pool = VK_NULL_HANDLE;
|
|
|
|
static VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
|
|
|
static VkFormat surface_format;
|
|
|
|
static std::vector<VkImage> swapchain_images;
|
|
|
|
static std::vector<VkImageView> swapchain_views;
|
|
|
|
static VkRenderPass render_pass = VK_NULL_HANDLE;
|
2022-10-04 10:07:35 -04:00
|
|
|
static VkImage depth_image = VK_NULL_HANDLE;
|
|
|
|
static VkDeviceMemory depth_memory = VK_NULL_HANDLE;
|
|
|
|
static VkImageView depth_view = VK_NULL_HANDLE;
|
|
|
|
static std::vector<VkFramebuffer> swapchain_framebuffers;
|
2022-10-04 09:34:57 -04:00
|
|
|
|
2022-10-04 10:01:45 -04:00
|
|
|
// TODO: removed hardcoded 3 frame queue, should be variable
|
|
|
|
static std::array<VkCommandBuffer, 3> command_buffers;
|
|
|
|
static std::array<VkSemaphore, 3> image_available;
|
|
|
|
static std::array<VkSemaphore, 3> render_finished;
|
|
|
|
static std::array<VkFence, 3> in_flight;
|
|
|
|
static uint32_t current_frame = 0;
|
|
|
|
static uint32_t image_index = 0;
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
static VkCommandBuffer current_cmd = VK_NULL_HANDLE;
|
2022-10-04 10:20:38 -04:00
|
|
|
|
2022-10-04 10:25:48 -04:00
|
|
|
static VkBuffer vertex_buffer = VK_NULL_HANDLE;
|
|
|
|
static VkDeviceMemory vertex_memory = VK_NULL_HANDLE;
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
struct ShaderProgramVulkan {
|
|
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
|
|
|
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::unordered_map<uint32_t, ShaderProgramVulkan*> cached_shaders;
|
|
|
|
|
|
|
|
static ShaderProgramVulkan* last_program = nullptr;
|
|
|
|
|
2022-10-04 09:34:57 -04:00
|
|
|
VKAPI_ATTR VkBool32 VKAPI_CALL
|
|
|
|
gfx_vulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|
|
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
|
|
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
|
|
|
void* pUserData) {
|
|
|
|
|
|
|
|
printf("%s\n", pCallbackData->pMessage);
|
|
|
|
|
|
|
|
return VK_FALSE;
|
|
|
|
}
|
|
|
|
|
2022-10-03 22:49:19 -04:00
|
|
|
static bool gfx_vulkan_renderer_z_is_from_0_to_1(void) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-10-04 10:20:38 -04:00
|
|
|
static VkShaderModule gfx_vulkan_create_shader_module(const uint32_t* code, const int length) {
|
|
|
|
VkShaderModuleCreateInfo create_info = {};
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
|
|
|
create_info.codeSize = length;
|
|
|
|
create_info.pCode = reinterpret_cast<const uint32_t*>(code);
|
|
|
|
|
|
|
|
VkShaderModule shader_module;
|
|
|
|
vkCreateShaderModule(device, &create_info, nullptr, &shader_module);
|
|
|
|
|
|
|
|
return shader_module;
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
2022-10-04 10:20:38 -04:00
|
|
|
// TODO: will be removed, just used for testing
|
|
|
|
static VkShaderModule gfx_vulkan_load_shader(const char* path) {
|
|
|
|
std::ifstream file(path, std::ios::ate | std::ios::binary);
|
|
|
|
|
|
|
|
size_t fileSize = (size_t) file.tellg();
|
|
|
|
std::vector<char> buffer(fileSize);
|
|
|
|
|
|
|
|
file.seekg(0);
|
|
|
|
file.read(buffer.data(), fileSize);
|
|
|
|
|
|
|
|
return gfx_vulkan_create_shader_module(reinterpret_cast<const uint32_t *>(buffer.data()), fileSize);
|
|
|
|
}
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
static std::string gfx_vulkan_create_vertex_shader(const CCFeatures features) {
|
|
|
|
std::string src = "#version 460 core\n";
|
|
|
|
|
|
|
|
const bool uses_textures = features.used_textures[0] || features.used_textures[1];
|
|
|
|
const bool uses_alpha = features.opt_alpha;
|
|
|
|
const bool uses_fog = features.opt_fog;
|
|
|
|
const bool needs_screenpos = features.opt_alpha && features.opt_noise;
|
|
|
|
|
|
|
|
src += "layout(location = 0) in vec4 position;\n";
|
|
|
|
|
|
|
|
int next_input = 1;
|
|
|
|
if(uses_textures) {
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec2 uv;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(needs_screenpos) {
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec4 screen_pos;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(uses_fog) {
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec4 fog;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// extra inputs?
|
|
|
|
for(int i = 0; i < features.num_inputs; i++) {
|
|
|
|
int size = uses_alpha ? 4 : 3;
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec" + std::to_string(size) + " input" + std::to_string(i + 1) + ";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
src += "void main() {\n";
|
|
|
|
|
|
|
|
src += "gl_Position = position;\n";
|
|
|
|
|
|
|
|
src += "}";
|
|
|
|
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::string gfx_vulkan_create_fragment_shader(const CCFeatures features) {
|
|
|
|
std::string src = "#version 460 core\n";
|
|
|
|
|
|
|
|
const bool uses_textures = features.used_textures[0] || features.used_textures[1];
|
|
|
|
const bool uses_alpha = features.opt_alpha;
|
|
|
|
const bool uses_fog = features.opt_fog;
|
|
|
|
const bool needs_screenpos = features.opt_alpha && features.opt_noise;
|
|
|
|
|
|
|
|
src += "layout(location = 0) out vec4 out_color;\n";
|
|
|
|
|
|
|
|
/*int next_input = 0;
|
|
|
|
if(uses_textures) {
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec2 uv;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(needs_screenpos) {
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec4 screen_pos;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if(uses_fog) {
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec4 fog;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// extra inputs?
|
|
|
|
for(int i = 0; i < features.num_inputs; i++) {
|
|
|
|
int size = uses_alpha ? 4 : 3;
|
|
|
|
src += "layout(location = " + std::to_string(next_input++) + ") in vec" + std::to_string(size) + " input" + std::to_string(i + 1) + ";\n";
|
|
|
|
}*/
|
|
|
|
|
|
|
|
src += "void main() {\n";
|
|
|
|
|
|
|
|
src += "out_color = vec4(1, 1, 0, 1);\n";
|
|
|
|
|
|
|
|
src += "}";
|
|
|
|
|
|
|
|
return src;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VkShaderModule gfx_vulkan_compile_glsl(const std::string& shader_src, const EShLanguage language) {
|
|
|
|
glslang::InitializeProcess(); // TODO: lol
|
|
|
|
|
|
|
|
const char* InputCString = shader_src.c_str();
|
|
|
|
|
|
|
|
glslang::TShader shader(language);
|
|
|
|
shader.setStrings(&InputCString, 1);
|
|
|
|
|
|
|
|
int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
|
|
|
|
|
|
|
|
shader.setEnvInput(glslang::EShSourceGlsl, language, glslang::EShClientVulkan, ClientInputSemanticsVersion);
|
|
|
|
|
|
|
|
// we are targeting vulkan 1.1, so that uses SPIR-V 1.3
|
|
|
|
shader.setEnvClient(glslang::EShClientVulkan, glslang::EShTargetVulkan_1_0);
|
|
|
|
shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0);
|
|
|
|
|
|
|
|
if (!shader.parse(&DefaultTBuiltInResource, 100, false, EShMsgDefault)) {
|
|
|
|
printf("%s\n", shader.getInfoLog());
|
|
|
|
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
glslang::TProgram Program;
|
|
|
|
Program.addShader(&shader);
|
|
|
|
|
|
|
|
if (!Program.link(EShMsgDefault)) {
|
|
|
|
printf("failed to link %s %s %s\n", shader_src.data(), shader.getInfoLog(), shader.getInfoDebugLog());
|
|
|
|
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<unsigned int> SpirV;
|
|
|
|
spv::SpvBuildLogger logger;
|
|
|
|
|
|
|
|
glslang::SpvOptions spvOptions;
|
|
|
|
spvOptions.generateDebugInfo = true;
|
|
|
|
|
|
|
|
glslang::GlslangToSpv(*Program.getIntermediate(language), SpirV, &logger, &spvOptions);
|
|
|
|
|
|
|
|
return gfx_vulkan_create_shader_module(SpirV.data(), SpirV.size() * sizeof(uint32_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
static std::pair<VkPipeline, VkPipelineLayout> gfx_vulkan_create_pipeline(const CCFeatures features) {
|
|
|
|
const std::string vertex_src = gfx_vulkan_create_vertex_shader(features);
|
|
|
|
const std::string fragment_src = gfx_vulkan_create_fragment_shader(features);
|
|
|
|
|
2022-10-04 10:20:38 -04:00
|
|
|
VkPipelineShaderStageCreateInfo vertex_stage = {};
|
|
|
|
vertex_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
|
|
vertex_stage.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
2022-10-05 09:44:17 -04:00
|
|
|
vertex_stage.module = gfx_vulkan_compile_glsl(vertex_src, EShLanguage::EShLangVertex);
|
2022-10-04 10:20:38 -04:00
|
|
|
vertex_stage.pName = "main";
|
|
|
|
|
|
|
|
VkPipelineShaderStageCreateInfo fragment_stage = {};
|
|
|
|
fragment_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
|
|
fragment_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
2022-10-05 09:44:17 -04:00
|
|
|
fragment_stage.module = gfx_vulkan_compile_glsl(fragment_src, EShLanguage::EShLangFragment);
|
2022-10-04 10:20:38 -04:00
|
|
|
fragment_stage.pName = "main";
|
|
|
|
|
|
|
|
std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages = { vertex_stage, fragment_stage };
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
const bool uses_textures = features.used_textures[0] || features.used_textures[1];
|
|
|
|
const bool uses_alpha = features.opt_alpha;
|
|
|
|
const bool uses_fog = features.opt_fog;
|
|
|
|
const bool needs_screenpos = features.opt_alpha && features.opt_noise;
|
|
|
|
|
|
|
|
int num_floats = 0;
|
|
|
|
int current_location = 1;
|
|
|
|
|
|
|
|
std::vector<VkVertexInputAttributeDescription> attributes;
|
2022-10-04 10:20:38 -04:00
|
|
|
|
|
|
|
VkVertexInputAttributeDescription position_attribute = {};
|
2022-10-04 10:34:29 -04:00
|
|
|
position_attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
2022-10-05 09:44:17 -04:00
|
|
|
num_floats += 4;
|
|
|
|
|
|
|
|
attributes.push_back(position_attribute);
|
|
|
|
|
|
|
|
if(uses_textures) {
|
|
|
|
VkVertexInputAttributeDescription uv_attribute = {};
|
|
|
|
uv_attribute.format = VK_FORMAT_R32G32_SFLOAT;
|
|
|
|
uv_attribute.location = current_location++;
|
|
|
|
uv_attribute.offset = num_floats * sizeof(float);
|
|
|
|
|
|
|
|
num_floats += 2;
|
|
|
|
|
|
|
|
attributes.push_back(uv_attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(needs_screenpos) {
|
|
|
|
VkVertexInputAttributeDescription screenpos_attribute = {};
|
|
|
|
screenpos_attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
|
|
screenpos_attribute.location = current_location++;
|
|
|
|
screenpos_attribute.offset = num_floats * sizeof(float);
|
|
|
|
|
|
|
|
num_floats += 4;
|
|
|
|
|
|
|
|
attributes.push_back(screenpos_attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(uses_fog) {
|
|
|
|
VkVertexInputAttributeDescription fog_attribute = {};
|
|
|
|
fog_attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
|
|
fog_attribute.location = current_location++;
|
|
|
|
fog_attribute.offset = num_floats * sizeof(float);
|
2022-10-04 10:20:38 -04:00
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
num_floats += 4;
|
|
|
|
|
|
|
|
attributes.push_back(fog_attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < features.num_inputs; i++) {
|
|
|
|
VkVertexInputAttributeDescription extra_attribute = {};
|
|
|
|
extra_attribute.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
|
|
|
extra_attribute.location = current_location++;
|
|
|
|
extra_attribute.offset = num_floats * sizeof(float);
|
|
|
|
|
|
|
|
num_floats += 4;
|
|
|
|
|
|
|
|
attributes.push_back(extra_attribute);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("uses textures: %d\n", uses_textures);
|
|
|
|
printf("needs screenpos: %d\n", needs_screenpos);
|
|
|
|
printf("uses fog: %d\n", uses_fog);
|
|
|
|
printf("extra inputs: %d\n", features.num_inputs);
|
|
|
|
|
|
|
|
VkVertexInputBindingDescription binding = {};
|
|
|
|
binding.stride = sizeof(float) * num_floats;
|
2022-10-04 10:20:38 -04:00
|
|
|
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertex_input_state = {};
|
|
|
|
vertex_input_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
|
|
vertex_input_state.vertexBindingDescriptionCount = 1;
|
|
|
|
vertex_input_state.pVertexBindingDescriptions = &binding;
|
|
|
|
vertex_input_state.vertexAttributeDescriptionCount = attributes.size();
|
|
|
|
vertex_input_state.pVertexAttributeDescriptions = attributes.data();
|
|
|
|
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
|
|
|
|
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
|
|
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
|
|
|
|
VkViewport viewport = {};
|
|
|
|
viewport.width = 640;
|
|
|
|
viewport.height = 480;
|
|
|
|
viewport.maxDepth = 1.0f;
|
|
|
|
|
|
|
|
VkRect2D scissor = {};
|
|
|
|
scissor.extent.width = 640;
|
|
|
|
scissor.extent.height = 480;
|
|
|
|
|
|
|
|
VkPipelineViewportStateCreateInfo viewport_state = {};
|
|
|
|
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
|
|
viewport_state.viewportCount = 1;
|
|
|
|
viewport_state.pViewports = &viewport;
|
|
|
|
viewport_state.scissorCount = 1;
|
|
|
|
viewport_state.pScissors = &scissor;
|
|
|
|
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterizer = {};
|
|
|
|
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
|
|
rasterizer.lineWidth = 1.0f;
|
2022-10-04 10:34:29 -04:00
|
|
|
rasterizer.cullMode = VK_CULL_MODE_NONE;
|
|
|
|
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
2022-10-04 10:20:38 -04:00
|
|
|
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisampling = {};
|
|
|
|
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
|
|
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
|
|
|
|
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
|
|
|
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
|
|
|
|
|
|
VkPipelineColorBlendStateCreateInfo color_blending = {};
|
|
|
|
color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
|
|
color_blending.attachmentCount = 1;
|
|
|
|
color_blending.pAttachments = &color_blend_attachment;
|
|
|
|
|
|
|
|
VkPipelineDynamicStateCreateInfo dynamic_state = {};
|
|
|
|
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
|
|
|
|
|
|
VkPipelineLayoutCreateInfo pipeline_layout_create_info = {};
|
|
|
|
pipeline_layout_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
VkPipelineLayout layout = VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
vkCreatePipelineLayout(device, &pipeline_layout_create_info, nullptr, &layout);
|
2022-10-04 10:20:38 -04:00
|
|
|
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depth_stencil = {};
|
|
|
|
depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
|
|
depth_stencil.depthTestEnable = VK_TRUE;
|
|
|
|
depth_stencil.depthWriteEnable = VK_TRUE;
|
|
|
|
depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS;
|
|
|
|
depth_stencil.maxDepthBounds = 1.0f;
|
|
|
|
|
|
|
|
VkGraphicsPipelineCreateInfo pipeline_create_info = {};
|
|
|
|
pipeline_create_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
|
|
pipeline_create_info.stageCount = shader_stages.size();
|
|
|
|
pipeline_create_info.pStages = shader_stages.data();
|
|
|
|
pipeline_create_info.pVertexInputState = &vertex_input_state;
|
|
|
|
pipeline_create_info.pInputAssemblyState = &input_assembly;
|
|
|
|
pipeline_create_info.pViewportState = &viewport_state;
|
|
|
|
pipeline_create_info.pRasterizationState = &rasterizer;
|
|
|
|
pipeline_create_info.pMultisampleState = &multisampling;
|
|
|
|
pipeline_create_info.pColorBlendState = &color_blending;
|
|
|
|
pipeline_create_info.pDynamicState = &dynamic_state;
|
|
|
|
pipeline_create_info.pDepthStencilState = &depth_stencil;
|
2022-10-05 09:44:17 -04:00
|
|
|
pipeline_create_info.layout = layout;
|
2022-10-04 10:20:38 -04:00
|
|
|
pipeline_create_info.renderPass = render_pass;
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
2022-10-04 10:20:38 -04:00
|
|
|
vkCreateGraphicsPipelines(device,
|
|
|
|
VK_NULL_HANDLE,
|
|
|
|
1,
|
|
|
|
&pipeline_create_info,
|
|
|
|
nullptr,
|
|
|
|
&pipeline);
|
2022-10-05 09:44:17 -04:00
|
|
|
|
|
|
|
return {pipeline, layout};
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
2022-10-05 09:44:17 -04:00
|
|
|
// FIXME: reorganize
|
|
|
|
static void gfx_vulkan_renderer_load_shader(struct ShaderProgram *new_prg);
|
|
|
|
|
2022-10-03 22:49:19 -04:00
|
|
|
static struct ShaderProgram *gfx_vulkan_renderer_create_and_load_new_shader(uint32_t shader_id) {
|
2022-10-05 09:44:17 -04:00
|
|
|
ShaderProgramVulkan* shader = new ShaderProgramVulkan();
|
|
|
|
|
|
|
|
CCFeatures cc_features;
|
|
|
|
gfx_cc_get_features(shader_id, &cc_features);
|
|
|
|
|
|
|
|
auto [pipeline, layout] = gfx_vulkan_create_pipeline(cc_features);
|
|
|
|
shader->pipeline = pipeline;
|
|
|
|
shader->pipeline_layout = layout;
|
|
|
|
|
|
|
|
cached_shaders[shader_id] = shader;
|
|
|
|
|
|
|
|
gfx_vulkan_renderer_load_shader(reinterpret_cast<ShaderProgram *>(shader));
|
|
|
|
|
|
|
|
return reinterpret_cast<ShaderProgram *>(shader);
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct ShaderProgram *gfx_vulkan_renderer_lookup_shader(uint32_t shader_id) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_shader_get_info(struct ShaderProgram *prg, uint8_t *num_inputs, bool used_textures[2]) {
|
|
|
|
*num_inputs = 0;
|
|
|
|
used_textures[0] = false;
|
|
|
|
used_textures[1] = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t gfx_vulkan_renderer_new_texture(void) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-10-04 10:07:35 -04:00
|
|
|
static uint32_t gfx_vulkan_find_memory_type(uint32_t type_filter, VkMemoryPropertyFlags properties) {
|
|
|
|
VkPhysicalDeviceMemoryProperties memory_properties;
|
|
|
|
vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; i++) {
|
|
|
|
if ((type_filter & (1 << i)) &&
|
|
|
|
(memory_properties.memoryTypes[i].propertyFlags & properties) ==
|
|
|
|
properties) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-10-04 09:34:57 -04:00
|
|
|
static void gfx_vulkan_create_instance() {
|
|
|
|
std::vector<const char*> instance_extensions = {"VK_EXT_debug_utils"};
|
|
|
|
|
|
|
|
uint32_t extension_count = 0;
|
|
|
|
vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, nullptr);
|
|
|
|
|
|
|
|
std::vector<VkExtensionProperties> extensions(extension_count);
|
|
|
|
vkEnumerateInstanceExtensionProperties(nullptr, &extension_count, extensions.data());
|
|
|
|
|
|
|
|
for(auto& extension : extensions) {
|
|
|
|
if (strstr(extension.extensionName, "surface") != nullptr) {
|
|
|
|
instance_extensions.push_back(extension.extensionName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(extension.extensionName, "VK_KHR_get_physical_device_properties2") != nullptr) {
|
|
|
|
instance_extensions.push_back(extension.extensionName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkDebugUtilsMessengerCreateInfoEXT debug_create_info = {};
|
|
|
|
debug_create_info.sType =
|
|
|
|
VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
|
|
|
debug_create_info.messageSeverity =
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
|
|
|
debug_create_info.messageType =
|
|
|
|
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
|
|
|
debug_create_info.pfnUserCallback = gfx_vulkan_debug_callback;
|
|
|
|
|
|
|
|
VkInstanceCreateInfo create_info = {};
|
|
|
|
create_info.pNext = &debug_create_info;
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
|
|
create_info.ppEnabledExtensionNames = instance_extensions.data();
|
|
|
|
create_info.enabledExtensionCount = instance_extensions.size();
|
|
|
|
|
|
|
|
vkCreateInstance(&create_info, nullptr, &instance);
|
|
|
|
|
|
|
|
printf("Created vulkan instance!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_create_command_pool(const int graphics_family_index) {
|
|
|
|
VkCommandPoolCreateInfo pool_create_info = {};
|
|
|
|
pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
|
|
pool_create_info.queueFamilyIndex = graphics_family_index;
|
|
|
|
pool_create_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
|
|
|
|
|
|
vkCreateCommandPool(device, &pool_create_info, nullptr, &command_pool);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_create_device() {
|
|
|
|
// pick physical device
|
|
|
|
uint32_t device_count = 0;
|
|
|
|
vkEnumeratePhysicalDevices(instance, &device_count, nullptr);
|
|
|
|
|
|
|
|
std::vector<VkPhysicalDevice> devices(device_count);
|
|
|
|
vkEnumeratePhysicalDevices(instance, &device_count, devices.data());
|
|
|
|
|
|
|
|
for (auto device : devices) {
|
|
|
|
VkPhysicalDeviceProperties device_properties;
|
|
|
|
vkGetPhysicalDeviceProperties(device, &device_properties);
|
|
|
|
|
|
|
|
printf("GPU Found: %s\n", device_properties.deviceName);
|
|
|
|
}
|
|
|
|
|
|
|
|
physical_device = devices[0];
|
|
|
|
|
|
|
|
uint32_t extension_count = 0;
|
|
|
|
vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
|
|
|
|
&extension_count, nullptr);
|
|
|
|
|
|
|
|
std::vector<VkExtensionProperties> extension_properties(extension_count);
|
|
|
|
vkEnumerateDeviceExtensionProperties(
|
|
|
|
physical_device, nullptr, &extension_count,
|
|
|
|
extension_properties.data());
|
|
|
|
|
|
|
|
uint32_t graphics_family_index = 0, present_family_index = 0;
|
|
|
|
|
|
|
|
// create logical device
|
|
|
|
uint32_t queue_family_count = 0;
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
|
|
|
|
nullptr);
|
|
|
|
|
|
|
|
std::vector<VkQueueFamilyProperties> queueFamilies(queue_family_count);
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
|
|
|
|
queueFamilies.data());
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
for (const auto&queue_family : queueFamilies) {
|
|
|
|
if (queue_family.queueCount > 0 && queue_family.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
|
|
|
graphics_family_index = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
|
|
|
|
|
|
|
if (graphics_family_index == present_family_index) {
|
|
|
|
VkDeviceQueueCreateInfo queue_create_info = {};
|
|
|
|
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
queue_create_info.queueFamilyIndex = graphics_family_index;
|
|
|
|
queue_create_info.queueCount = 1;
|
|
|
|
|
|
|
|
float queuePriority = 1.0f;
|
|
|
|
queue_create_info.pQueuePriorities = &queuePriority;
|
|
|
|
|
|
|
|
queue_create_infos.push_back(queue_create_info);
|
|
|
|
} else {
|
|
|
|
// graphics
|
|
|
|
{
|
|
|
|
VkDeviceQueueCreateInfo queue_create_info = {};
|
|
|
|
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
queue_create_info.queueFamilyIndex = graphics_family_index;
|
|
|
|
queue_create_info.queueCount = 1;
|
|
|
|
|
|
|
|
float queuePriority = 1.0f;
|
|
|
|
queue_create_info.pQueuePriorities = &queuePriority;
|
|
|
|
|
|
|
|
queue_create_infos.push_back(queue_create_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
// present
|
|
|
|
{
|
|
|
|
VkDeviceQueueCreateInfo queue_create_info = {};
|
|
|
|
queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
queue_create_info.queueFamilyIndex = present_family_index;
|
|
|
|
queue_create_info.queueCount = 1;
|
|
|
|
|
|
|
|
float queuePriority = 1.0f;
|
|
|
|
queue_create_info.pQueuePriorities = &queuePriority;
|
|
|
|
|
|
|
|
queue_create_infos.push_back(queue_create_info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 09:53:38 -04:00
|
|
|
std::array<const char*, 1> device_extensions = {"VK_KHR_swapchain"};
|
|
|
|
|
2022-10-04 09:34:57 -04:00
|
|
|
VkDeviceCreateInfo device_create_info = {};
|
|
|
|
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
|
|
|
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
|
|
|
device_create_info.queueCreateInfoCount =
|
|
|
|
static_cast<uint32_t>(queue_create_infos.size());
|
2022-10-04 09:53:38 -04:00
|
|
|
device_create_info.ppEnabledExtensionNames = device_extensions.data();
|
|
|
|
device_create_info.enabledExtensionCount = device_extensions.size();
|
2022-10-04 09:34:57 -04:00
|
|
|
|
|
|
|
vkCreateDevice(physical_device, &device_create_info, nullptr, &device);
|
|
|
|
|
|
|
|
printf("Created vulkan device!\n");
|
|
|
|
|
|
|
|
vkGetDeviceQueue(device, graphics_family_index, 0, &graphics_queue);
|
|
|
|
vkGetDeviceQueue(device, present_family_index, 0, &present_queue);
|
|
|
|
|
|
|
|
gfx_vulkan_create_command_pool(graphics_family_index);
|
|
|
|
}
|
|
|
|
|
2022-10-04 09:53:38 -04:00
|
|
|
static void gfx_vulkan_create_swapchain() {
|
|
|
|
vkQueueWaitIdle(present_queue);
|
|
|
|
|
|
|
|
// create surface from wapi
|
|
|
|
VkSurfaceKHR surface =
|
|
|
|
static_cast<VkSurfaceKHR>(gfx_get_current_windowing_api()->create_surface(instance));
|
|
|
|
|
|
|
|
VkBool32 supported;
|
|
|
|
vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, 0,
|
|
|
|
surface, &supported);
|
|
|
|
|
|
|
|
// query swapchain support
|
|
|
|
VkSurfaceCapabilitiesKHR capabilities;
|
|
|
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
|
|
|
|
physical_device, surface, &capabilities);
|
|
|
|
|
|
|
|
std::vector<VkSurfaceFormatKHR> formats;
|
|
|
|
|
|
|
|
uint32_t format_count;
|
|
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(
|
|
|
|
physical_device, surface, &format_count, nullptr);
|
|
|
|
|
|
|
|
formats.resize(format_count);
|
|
|
|
vkGetPhysicalDeviceSurfaceFormatsKHR(
|
|
|
|
physical_device, surface, &format_count, formats.data());
|
|
|
|
|
|
|
|
std::vector<VkPresentModeKHR> present_modes;
|
|
|
|
uint32_t present_mode_count;
|
|
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
|
|
|
physical_device, surface, &present_mode_count, nullptr);
|
|
|
|
|
|
|
|
present_modes.resize(present_mode_count);
|
|
|
|
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
|
|
|
physical_device, surface, &present_mode_count,
|
|
|
|
present_modes.data());
|
|
|
|
|
|
|
|
// choosing swapchain features
|
|
|
|
surface_format = formats[0].format;
|
|
|
|
for (const auto& available_format : formats) {
|
|
|
|
if (available_format.format == VK_FORMAT_B8G8R8A8_UNORM && available_format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
|
|
|
|
surface_format = available_format.format;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR;
|
|
|
|
for (const auto& available_mode : present_modes) {
|
|
|
|
if (available_mode == VK_PRESENT_MODE_MAILBOX_KHR) {
|
|
|
|
present_mode = available_mode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t image_count = capabilities.minImageCount + 1;
|
|
|
|
if (capabilities.maxImageCount > 0 && image_count > capabilities.maxImageCount) {
|
|
|
|
image_count = capabilities.maxImageCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
// create swapchain
|
|
|
|
VkSwapchainCreateInfoKHR swapchain_create_info = {};
|
|
|
|
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
|
|
|
swapchain_create_info.surface = surface;
|
|
|
|
swapchain_create_info.minImageCount = image_count;
|
|
|
|
swapchain_create_info.imageFormat = surface_format;
|
|
|
|
swapchain_create_info.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; // FIXME: hardcoded
|
|
|
|
swapchain_create_info.imageExtent.width = 640; // FIXME: hardcoded
|
|
|
|
swapchain_create_info.imageExtent.height = 480;
|
|
|
|
swapchain_create_info.imageArrayLayers = 1;
|
|
|
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
|
|
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
swapchain_create_info.preTransform = capabilities.currentTransform;
|
|
|
|
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
|
|
|
swapchain_create_info.presentMode = present_mode;
|
|
|
|
swapchain_create_info.clipped = VK_TRUE;
|
|
|
|
|
|
|
|
VkSwapchainKHR old_swapchain = swapchain;
|
|
|
|
swapchain_create_info.oldSwapchain = old_swapchain;
|
|
|
|
|
|
|
|
vkCreateSwapchainKHR(device, &swapchain_create_info, nullptr, &swapchain);
|
|
|
|
|
|
|
|
if(old_swapchain != VK_NULL_HANDLE) {
|
|
|
|
vkDestroySwapchainKHR(device, old_swapchain, nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
vkGetSwapchainImagesKHR(device, swapchain, &image_count,
|
|
|
|
nullptr);
|
|
|
|
swapchain_images.resize(image_count);
|
|
|
|
vkGetSwapchainImagesKHR(device, swapchain, &image_count, swapchain_images.data());
|
|
|
|
|
|
|
|
swapchain_views.resize(swapchain_images.size());
|
|
|
|
|
|
|
|
for (size_t i = 0; i < swapchain_images.size(); i++) {
|
|
|
|
VkImageViewCreateInfo view_create_info = {};
|
|
|
|
view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
|
|
view_create_info.image = swapchain_images[i];
|
|
|
|
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
view_create_info.format = surface_format;
|
|
|
|
view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
|
|
|
view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
|
|
|
view_create_info.subresourceRange.baseMipLevel = 0;
|
|
|
|
view_create_info.subresourceRange.levelCount = 1;
|
|
|
|
view_create_info.subresourceRange.baseArrayLayer = 0;
|
|
|
|
view_create_info.subresourceRange.layerCount = 1;
|
|
|
|
|
|
|
|
vkCreateImageView(device, &view_create_info, nullptr,&swapchain_views[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Initialized swap chain!\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_create_render_pass() {
|
|
|
|
VkAttachmentDescription color_attachment = {};
|
|
|
|
color_attachment.format = surface_format;
|
|
|
|
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
|
|
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
|
|
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
|
|
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
|
|
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
|
|
|
|
|
|
|
VkAttachmentReference color_attachment_ref = {};
|
|
|
|
color_attachment_ref.attachment = 0;
|
|
|
|
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
|
|
|
|
|
|
|
VkAttachmentDescription depth_attachment = {};
|
|
|
|
depth_attachment.format = VK_FORMAT_D32_SFLOAT;
|
|
|
|
depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
|
|
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
|
|
|
depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
|
|
depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
|
|
depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
depth_attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
|
|
|
|
|
|
VkAttachmentReference depth_attachment_ref = {};
|
|
|
|
depth_attachment_ref.attachment = 1;
|
|
|
|
depth_attachment_ref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
|
|
|
|
|
|
|
VkSubpassDependency dependency = {};
|
|
|
|
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
|
|
|
dependency.dstSubpass = 0;
|
|
|
|
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
|
|
|
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
|
|
|
dependency.srcAccessMask = 0;
|
|
|
|
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
|
|
|
dependency.dependencyFlags = 0;
|
|
|
|
|
|
|
|
VkSubpassDescription subpass = {};
|
|
|
|
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
|
|
|
subpass.colorAttachmentCount = 1;
|
|
|
|
subpass.pColorAttachments = &color_attachment_ref;
|
|
|
|
subpass.pDepthStencilAttachment = &depth_attachment_ref;
|
|
|
|
|
|
|
|
std::array<VkAttachmentDescription, 2> attachments = { color_attachment, depth_attachment };
|
|
|
|
|
|
|
|
VkRenderPassCreateInfo render_pass_create_info = {};
|
|
|
|
render_pass_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
|
|
|
render_pass_create_info.attachmentCount = attachments.size();
|
|
|
|
render_pass_create_info.pAttachments = attachments.data();
|
|
|
|
render_pass_create_info.subpassCount = 1;
|
|
|
|
render_pass_create_info.pSubpasses = &subpass;
|
|
|
|
render_pass_create_info.dependencyCount = 1;
|
|
|
|
render_pass_create_info.pDependencies = &dependency;
|
|
|
|
|
|
|
|
vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
|
|
|
|
}
|
|
|
|
|
2022-10-04 10:01:45 -04:00
|
|
|
static void gfx_vulkan_create_sync() {
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
|
|
VkCommandBufferAllocateInfo allocate_info = {};
|
|
|
|
allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
|
|
allocate_info.commandPool = command_pool;
|
|
|
|
allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
|
|
allocate_info.commandBufferCount = 1;
|
|
|
|
|
|
|
|
vkAllocateCommandBuffers(device, &allocate_info, &command_buffers[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
VkSemaphoreCreateInfo semaphore_create_info = {};
|
|
|
|
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
|
|
|
|
|
|
|
VkFenceCreateInfo fence_create_info = {};
|
|
|
|
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
|
|
|
fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < 3; i++) {
|
|
|
|
vkCreateSemaphore(device, &semaphore_create_info, nullptr, &image_available[i]);
|
|
|
|
vkCreateSemaphore(device, &semaphore_create_info, nullptr, &render_finished[i]);
|
|
|
|
vkCreateFence(device, &fence_create_info, nullptr, &in_flight[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 10:07:35 -04:00
|
|
|
static void gfx_vulkan_create_depth() {
|
|
|
|
VkImageCreateInfo image_create_info = {};
|
|
|
|
image_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
|
|
|
image_create_info.imageType = VK_IMAGE_TYPE_2D;
|
|
|
|
image_create_info.extent.width = 640;
|
|
|
|
image_create_info.extent.height = 480;
|
|
|
|
image_create_info.extent.depth = 1;
|
|
|
|
image_create_info.mipLevels = 1;
|
|
|
|
image_create_info.arrayLayers = 1;
|
|
|
|
image_create_info.format = VK_FORMAT_D32_SFLOAT;
|
|
|
|
image_create_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
|
|
|
image_create_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
|
|
|
image_create_info.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
|
|
|
image_create_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
image_create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
|
|
|
|
vkCreateImage(device, &image_create_info, nullptr, &depth_image);
|
|
|
|
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetImageMemoryRequirements(device, depth_image, &memory_requirements);
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo allocate_info = {};
|
|
|
|
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
|
|
allocate_info.allocationSize = memory_requirements.size;
|
|
|
|
allocate_info.memoryTypeIndex = gfx_vulkan_find_memory_type(memory_requirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
|
|
|
|
|
|
|
vkAllocateMemory(device, &allocate_info, nullptr, &depth_memory);
|
|
|
|
|
|
|
|
vkBindImageMemory(device, depth_image, depth_memory, 0);
|
|
|
|
|
|
|
|
VkImageViewCreateInfo view_create_info = {};
|
|
|
|
view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
|
|
view_create_info.image = depth_image;
|
|
|
|
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
|
|
|
view_create_info.format = VK_FORMAT_D32_SFLOAT;
|
|
|
|
view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
|
|
|
view_create_info.subresourceRange.levelCount = 1;
|
|
|
|
view_create_info.subresourceRange.layerCount = 1;
|
|
|
|
|
|
|
|
vkCreateImageView(device, &view_create_info, nullptr, &depth_view);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_create_framebuffers() {
|
|
|
|
swapchain_framebuffers.resize(swapchain_views.size());
|
|
|
|
|
|
|
|
for (size_t i = 0; i < swapchain_framebuffers.size(); i++) {
|
|
|
|
std::array<VkImageView, 2> attachments = {swapchain_views[i], depth_view};
|
|
|
|
|
|
|
|
VkFramebufferCreateInfo create_info = {};
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
|
|
|
create_info.renderPass = render_pass;
|
|
|
|
create_info.attachmentCount = attachments.size();
|
|
|
|
create_info.pAttachments = attachments.data();
|
|
|
|
create_info.width = 640;
|
|
|
|
create_info.height = 480;
|
|
|
|
create_info.layers = 1;
|
|
|
|
|
|
|
|
vkCreateFramebuffer(device, &create_info, nullptr, &swapchain_framebuffers[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 10:25:48 -04:00
|
|
|
static void gfx_vulkan_create_buffers() {
|
|
|
|
vkDeviceWaitIdle(device);
|
|
|
|
|
|
|
|
// create buffer
|
|
|
|
VkBufferCreateInfo create_info = {};
|
|
|
|
create_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
|
|
create_info.size = 60000;
|
|
|
|
create_info.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
|
|
create_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
|
|
|
|
|
|
vkCreateBuffer(device, &create_info, nullptr, &vertex_buffer);
|
|
|
|
|
|
|
|
// allocate memory
|
|
|
|
VkMemoryRequirements memory_requirements;
|
|
|
|
vkGetBufferMemoryRequirements(device, vertex_buffer, &memory_requirements);
|
|
|
|
|
|
|
|
VkMemoryAllocateInfo allocate_info = {};
|
|
|
|
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
|
|
allocate_info.allocationSize = memory_requirements.size;
|
|
|
|
allocate_info.memoryTypeIndex =
|
|
|
|
gfx_vulkan_find_memory_type(memory_requirements.memoryTypeBits,
|
|
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
|
|
|
|
|
|
|
vkAllocateMemory(device, &allocate_info, nullptr, &vertex_memory);
|
|
|
|
|
|
|
|
vkBindBufferMemory(device, vertex_buffer, vertex_memory, 0);
|
|
|
|
}
|
|
|
|
|
2022-10-03 22:49:19 -04:00
|
|
|
static void gfx_vulkan_renderer_init(void) {
|
2022-10-04 09:34:57 -04:00
|
|
|
gfx_vulkan_create_instance();
|
|
|
|
gfx_vulkan_create_device();
|
2022-10-04 09:53:38 -04:00
|
|
|
gfx_vulkan_create_swapchain();
|
|
|
|
gfx_vulkan_create_render_pass();
|
2022-10-04 10:01:45 -04:00
|
|
|
gfx_vulkan_create_sync();
|
2022-10-04 10:07:35 -04:00
|
|
|
gfx_vulkan_create_depth();
|
|
|
|
gfx_vulkan_create_framebuffers();
|
2022-10-04 10:25:48 -04:00
|
|
|
gfx_vulkan_create_buffers();
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_on_resize(void) {
|
2022-10-04 09:34:57 -04:00
|
|
|
// doesn't seem to be called?
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_start_frame(void) {
|
2022-10-04 10:01:45 -04:00
|
|
|
vkWaitForFences(
|
|
|
|
device, 1,
|
|
|
|
&in_flight[current_frame],
|
|
|
|
VK_TRUE, std::numeric_limits<uint64_t>::max());
|
|
|
|
|
|
|
|
image_index = 0;
|
|
|
|
VkResult result = vkAcquireNextImageKHR(
|
|
|
|
device, swapchain,
|
|
|
|
std::numeric_limits<uint64_t>::max(),
|
|
|
|
image_available[current_frame],
|
|
|
|
VK_NULL_HANDLE, &image_index);
|
|
|
|
|
|
|
|
if (result == VK_ERROR_OUT_OF_DATE_KHR) {
|
|
|
|
printf("Swapchain is out of date!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
current_cmd = command_buffers[current_frame];
|
|
|
|
|
2022-10-04 10:07:35 -04:00
|
|
|
VkCommandBufferBeginInfo buffer_begin = {};
|
|
|
|
buffer_begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
|
|
buffer_begin.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
|
|
|
|
|
|
|
|
vkBeginCommandBuffer(current_cmd, &buffer_begin);
|
|
|
|
|
|
|
|
VkRenderPassBeginInfo render_pass_begin = {};
|
|
|
|
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
|
|
|
render_pass_begin.renderPass = render_pass;
|
|
|
|
render_pass_begin.framebuffer = swapchain_framebuffers[image_index];
|
|
|
|
|
|
|
|
std::array<VkClearValue, 2> clear_values = {};
|
|
|
|
clear_values[0].color.float32[0] = 0.8;
|
|
|
|
clear_values[0].color.float32[1] = 0.8;
|
|
|
|
clear_values[0].color.float32[2] = 0.8;
|
|
|
|
clear_values[0].color.float32[3] = 1.0;
|
|
|
|
clear_values[1].depthStencil = {1.0f, 0};
|
|
|
|
|
|
|
|
render_pass_begin.clearValueCount = clear_values.size();
|
|
|
|
render_pass_begin.pClearValues = clear_values.data();
|
|
|
|
render_pass_begin.renderArea.extent.width = 640;
|
|
|
|
render_pass_begin.renderArea.extent.height = 480;
|
2022-10-04 10:01:45 -04:00
|
|
|
|
2022-10-04 10:07:35 -04:00
|
|
|
vkCmdBeginRenderPass(current_cmd, &render_pass_begin, VK_SUBPASS_CONTENTS_INLINE);
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
2022-10-04 10:20:38 -04:00
|
|
|
/* draw commands */
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_select_texture(int tile, uint32_t texture_id) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_upload_texture(const uint8_t *rgba32_buf, int width, int height) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_sampler_parameters(int tile, bool linear_filter, uint32_t cms, uint32_t cmt) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_depth_test(bool depth_test) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_depth_mask(bool z_upd) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_zmode_decal(bool zmode_decal) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_viewport(int x, int y, int width, int height) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_scissor(int x, int y, int width, int height) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_set_use_alpha(bool use_alpha) {
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_unload_shader(struct ShaderProgram *old_prg) {
|
2022-10-05 09:44:17 -04:00
|
|
|
|
2022-10-04 10:20:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_load_shader(struct ShaderProgram *new_prg) {
|
2022-10-05 09:44:17 -04:00
|
|
|
ShaderProgramVulkan* vulkan = (ShaderProgramVulkan*)new_prg;
|
|
|
|
|
|
|
|
if(current_cmd != VK_NULL_HANDLE) {
|
|
|
|
vkCmdBindPipeline(current_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan->pipeline);
|
|
|
|
}
|
|
|
|
|
|
|
|
last_program = vulkan;
|
2022-10-04 10:20:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_draw_triangles(float buf_vbo[], size_t buf_vbo_len, size_t buf_vbo_num_tris) {
|
2022-10-05 09:44:17 -04:00
|
|
|
if(last_program != nullptr) {
|
|
|
|
gfx_vulkan_renderer_load_shader(reinterpret_cast<ShaderProgram *>(last_program));
|
|
|
|
}
|
2022-10-04 10:20:38 -04:00
|
|
|
|
2022-10-04 10:25:48 -04:00
|
|
|
void* mapped_data = nullptr;
|
|
|
|
vkMapMemory(device, vertex_memory, 0, buf_vbo_len, 0, &mapped_data);
|
|
|
|
|
2022-10-04 10:34:29 -04:00
|
|
|
memcpy(mapped_data, buf_vbo, buf_vbo_len * sizeof(float));
|
2022-10-04 10:25:48 -04:00
|
|
|
|
|
|
|
VkMappedMemoryRange range = {};
|
|
|
|
range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
|
|
|
|
range.memory = vertex_memory;
|
|
|
|
range.size = buf_vbo_len;
|
|
|
|
vkFlushMappedMemoryRanges(device, 1, &range);
|
|
|
|
|
|
|
|
vkUnmapMemory(device, vertex_memory);
|
|
|
|
|
|
|
|
VkDeviceSize offsets[] = {0};
|
|
|
|
vkCmdBindVertexBuffers(current_cmd, 0, 1, &vertex_buffer, offsets);
|
|
|
|
|
2022-10-04 10:34:29 -04:00
|
|
|
vkCmdDraw(current_cmd, buf_vbo_num_tris * 3, 1, 0, 0);
|
2022-10-04 10:20:38 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* end draw commands */
|
|
|
|
|
2022-10-03 22:49:19 -04:00
|
|
|
static void gfx_vulkan_renderer_end_frame(void) {
|
2022-10-04 10:07:35 -04:00
|
|
|
vkCmdEndRenderPass(current_cmd);
|
2022-10-04 10:01:45 -04:00
|
|
|
vkEndCommandBuffer(current_cmd);
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void gfx_vulkan_renderer_finish_render(void) {
|
2022-10-04 10:01:45 -04:00
|
|
|
VkSubmitInfo submit_info = {};
|
|
|
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
|
|
|
|
VkSemaphore wait_semaphores[] = {image_available[current_frame]};
|
|
|
|
VkPipelineStageFlags wait_stages[] = {
|
|
|
|
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
|
|
|
submit_info.waitSemaphoreCount = 1;
|
|
|
|
submit_info.pWaitSemaphores = wait_semaphores;
|
|
|
|
submit_info.pWaitDstStageMask = wait_stages;
|
|
|
|
submit_info.commandBufferCount = 1;
|
|
|
|
submit_info.pCommandBuffers = ¤t_cmd;
|
|
|
|
|
|
|
|
VkSemaphore signal_semaphores[] = {render_finished[current_frame]};
|
|
|
|
submit_info.signalSemaphoreCount = 1;
|
|
|
|
submit_info.pSignalSemaphores = signal_semaphores;
|
|
|
|
|
|
|
|
vkResetFences(device, 1, &in_flight[current_frame]);
|
|
|
|
|
|
|
|
if (vkQueueSubmit(graphics_queue, 1, &submit_info, in_flight[current_frame]) != VK_SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// present
|
|
|
|
VkPresentInfoKHR present_info = {};
|
|
|
|
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
|
|
|
|
|
|
|
present_info.waitSemaphoreCount = 1;
|
|
|
|
present_info.pWaitSemaphores = signal_semaphores;
|
|
|
|
VkSwapchainKHR swapChains[] = {swapchain};
|
|
|
|
present_info.swapchainCount = 1;
|
|
|
|
present_info.pSwapchains = swapChains;
|
|
|
|
present_info.pImageIndices = &image_index;
|
|
|
|
|
|
|
|
vkQueuePresentKHR(present_queue, &present_info);
|
|
|
|
|
|
|
|
current_frame = (current_frame + 1) % 3;
|
2022-10-05 09:44:17 -04:00
|
|
|
current_cmd = VK_NULL_HANDLE;
|
2022-10-03 22:49:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char* gfx_vulkan_get_name() {
|
|
|
|
return "Vulkan";
|
|
|
|
}
|
|
|
|
|
|
|
|
struct GfxRenderingAPI gfx_vulkan_api = {
|
|
|
|
gfx_vulkan_renderer_z_is_from_0_to_1,
|
|
|
|
gfx_vulkan_renderer_unload_shader,
|
|
|
|
gfx_vulkan_renderer_load_shader,
|
|
|
|
gfx_vulkan_renderer_create_and_load_new_shader,
|
|
|
|
gfx_vulkan_renderer_lookup_shader,
|
|
|
|
gfx_vulkan_renderer_shader_get_info,
|
|
|
|
gfx_vulkan_renderer_new_texture,
|
|
|
|
gfx_vulkan_renderer_select_texture,
|
|
|
|
gfx_vulkan_renderer_upload_texture,
|
|
|
|
gfx_vulkan_renderer_set_sampler_parameters,
|
|
|
|
gfx_vulkan_renderer_set_depth_test,
|
|
|
|
gfx_vulkan_renderer_set_depth_mask,
|
|
|
|
gfx_vulkan_renderer_set_zmode_decal,
|
|
|
|
gfx_vulkan_renderer_set_viewport,
|
|
|
|
gfx_vulkan_renderer_set_scissor,
|
|
|
|
gfx_vulkan_renderer_set_use_alpha,
|
|
|
|
gfx_vulkan_renderer_draw_triangles,
|
|
|
|
gfx_vulkan_renderer_init,
|
|
|
|
gfx_vulkan_renderer_on_resize,
|
|
|
|
gfx_vulkan_renderer_start_frame,
|
|
|
|
gfx_vulkan_renderer_end_frame,
|
|
|
|
gfx_vulkan_renderer_finish_render,
|
|
|
|
gfx_vulkan_get_name,
|
|
|
|
};
|