Files
funnygame/engine/vk_video.cpp
2025-07-20 00:45:31 +03:00

1412 lines
48 KiB
C++

#include "interface.h"
#include "math3d.h"
#include "filesystem.h"
#include "rendering.h"
#include "tier0/lib.h"
#include "tier1/utlvector.h"
#include "tier0/platform.h"
#include "rendering.h"
#include "vk_helper.h"
#include "vulkan/vulkan_core.h"
#include "tier0/mem.h"
#define STB_IMAGE_IMPLEMENTATION
#if defined(__APPLE__) && defined(__MACH__)
#include "TargetConditionals.h"
#if TARGET_OS_IPHONE
// iOS
#define STBI_NO_THREAD_LOCALS
#else
// macOS
#endif
#else
// Other platforms
#endif
#include "stb_image.h"
#define VULKAN_RENDERING_IMPLEMENTATION
#include "vk_video.h"
VkSampler g_invalidTextureSampler;
static CVkImage s_SwapchainImage;
IBuffer *g_cameraProperties;
struct CameraProjection {
mat4 viewprojection;
};
CameraProjection *g_cameraDataMap;
mat4 g_cameraView;
IImage *g_meshDepth;
IImage *g_meshDepthMSAA;
IImage *g_meshColor;
IImage *g_meshColorMSAA;
class CVkGraphicsPipeline: public IGraphicsPipeline
{
public:
vk_tripipeline_t m_pipeline;
uint32_t nVertexSize;
CUtlVector<VkWriteDescriptorSet> m_writes;
VkDescriptorPool m_descriptorPool;
VkDescriptorSet m_descriptorSet;
CUtlVector<ShaderInput_t> m_inputs;
virtual void PushBindings() override;
virtual void BindData( uint32_t binding, IBuffer *pBuffer, IImage* pImage) override;
};
void CVkGraphicsPipeline::BindData( uint32_t binding, IBuffer *pBuffer, IImage* pImage)
{
CVkBuffer* pVkBuffer = (CVkBuffer*)pBuffer;
VkDescriptorBufferInfo dbi;
for (auto &input: m_inputs)
{
if (input.binding != binding)
continue;
switch (input.type)
{
case SHADER_INPUT_TYPE_STORAGE_BUFFER:
case SHADER_INPUT_TYPE_UNIFORM_BUFFER:
if (!pBuffer)
Plat_FatalErrorFunc("pBuffer is NULL\n");
if (m_writes[binding].pBufferInfo)
V_free((void*)m_writes[binding].pBufferInfo);
dbi = {
.buffer = pVkBuffer->m_buffer.m_buffer,
.offset = 0,
.range = pVkBuffer->m_buffer.m_nSize,
};
m_writes[binding].pBufferInfo = (VkDescriptorBufferInfo*)V_malloc(sizeof(VkDescriptorBufferInfo));
V_memcpy((void*)m_writes[binding].pBufferInfo, &dbi, sizeof(VkDescriptorBufferInfo));
break;
case SHADER_INPUT_TYPE_IMAGE:
break;
case SHADER_INPUT_TYPE_TLAS:
break;
case SHADER_INPUT_TYPE_TEXTURES:
break;
};
}
}
void CVkGraphicsPipeline::PushBindings()
{
CUtlVector<VkDescriptorImageInfo> textures;
textures.Reserve(g_textures.GetSize());
for (ITexture *t: g_textures)
{
CVkTexture *texture = (CVkTexture*)t;
VkDescriptorImageInfo image = {};
image.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image.imageView = texture->image.m_imageView;
image.sampler = g_invalidTextureSampler;
textures.AppendTail(image);
};
for ( int i = 0; i < m_inputs.GetSize(); i++ )
{
if (m_inputs[i].type == SHADER_INPUT_TYPE_TEXTURES)
{
m_writes[i].descriptorCount = textures.GetSize();
m_writes[i].pImageInfo = textures.GetData();
}
}
textures[0].sampler = g_invalidTextureSampler;
vkUpdateDescriptorSets(g_vkDevice, m_writes.GetSize(), m_writes.GetData(), 0, NULL);
}
class CVkComputePipeline: public IComputePipeline
{
public:
vk_comppipeline_t m_pipeline;
};
class CVkRayTracingPipeline: public IRayTracingPipeline
{
public:
};
VkFormat IRenderer_FormatToVk( EImageFormat format )
{
switch (format)
{
case IMAGE_FORMAT_R8G8B8A8: return VK_FORMAT_R8G8B8A8_UNORM;
case IMAGE_FORMAT_R16G16B16A16: return VK_FORMAT_R16G16B16A16_UNORM;
case IMAGE_FORMAT_DEPTH: return VK_FORMAT_D32_SFLOAT;
case IMAGE_FORMAT_WINDOW: return g_swapchainFormat;
default: return VK_FORMAT_R8G8B8A8_UNORM;
}
};
VkFormat IRenderer_VertexToVk( EVertexFormat format )
{
switch (format)
{
case VERTEX_FORMAT_X16: return VK_FORMAT_R16_SFLOAT;
case VERTEX_FORMAT_X16Y16: return VK_FORMAT_R16G16_SFLOAT;
case VERTEX_FORMAT_X16Y16Z16: return VK_FORMAT_R16G16B16_SFLOAT;
case VERTEX_FORMAT_X16Y16Z16W16: return VK_FORMAT_R16G16B16A16_SFLOAT;
case VERTEX_FORMAT_X32: return VK_FORMAT_R32_SFLOAT;
case VERTEX_FORMAT_X32Y32: return VK_FORMAT_R32G32_SFLOAT;
case VERTEX_FORMAT_X32Y32Z32: return VK_FORMAT_R32G32B32_SFLOAT;
case VERTEX_FORMAT_X32Y32Z32W32: return VK_FORMAT_R32G32B32A32_SFLOAT;
}
};
uint32_t IRenderer_VertexToSize( EVertexFormat format )
{
switch (format)
{
case VERTEX_FORMAT_X16: return 2;
case VERTEX_FORMAT_X16Y16: return 4;
case VERTEX_FORMAT_X16Y16Z16: return 6;
case VERTEX_FORMAT_X16Y16Z16W16: return 8;
case VERTEX_FORMAT_X32: return 4;
case VERTEX_FORMAT_X32Y32: return 8;
case VERTEX_FORMAT_X32Y32Z32: return 12;
case VERTEX_FORMAT_X32Y32Z32W32: return 16;
}
}
VkAttachmentLoadOp IRenderer_LoadOpVk( EAttachmentLoadMode mode )
{
switch (mode)
{
case ATTACHMENT_LOAD_MODE_DONT_CARE: return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
case ATTACHMENT_LOAD_MODE_CLEAR: return VK_ATTACHMENT_LOAD_OP_CLEAR;
case ATTACHMENT_LOAD_MODE_LOAD: return VK_ATTACHMENT_LOAD_OP_LOAD;
default: return VK_ATTACHMENT_LOAD_OP_DONT_CARE;
}
}
VkAttachmentStoreOp IRenderer_StoreOpVk( EAttachmentStoreMode mode )
{
switch (mode)
{
case ATTACHMENT_STORE_MODE_DONT_CARE: return VK_ATTACHMENT_STORE_OP_DONT_CARE;
case ATTACHMENT_STORE_MODE_STORE: return VK_ATTACHMENT_STORE_OP_STORE;
default: return VK_ATTACHMENT_STORE_OP_DONT_CARE;
}
}
void IVulkan::Init()
{
char invalidTexture[1024] = {};
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
int index = i * 16 + j;
if ((i + j) % 2 == 0) {
invalidTexture[index*4] = 255;
}
}
}
ITextureManager::LoadTexture(invalidTexture, 16, 16, 4);
VkPhysicalDeviceProperties properties{};
vkGetPhysicalDeviceProperties(g_vkPhysicalDevice, &properties);
VkSamplerCreateInfo samplerInfo{};
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.magFilter = VK_FILTER_LINEAR;
samplerInfo.minFilter = VK_FILTER_LINEAR;
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
samplerInfo.anisotropyEnable = VK_FALSE;
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
samplerInfo.unnormalizedCoordinates = VK_FALSE;
samplerInfo.compareEnable = VK_FALSE;
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerInfo.mipLodBias = 0.0f;
samplerInfo.minLod = 0.0f;
samplerInfo.maxLod = 0.0f;
vkCreateSampler(g_vkDevice, &samplerInfo, nullptr, &g_invalidTextureSampler);
g_cameraProperties = Renderer()->CreateUniformBuffer(sizeof(CameraProjection));
g_cameraDataMap = (CameraProjection*)g_cameraProperties->Map();
g_meshDepth = Renderer()->CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, 1280, 720, 1);
g_meshDepthMSAA = Renderer()->CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, 1280, 720, 4);
g_meshColor = Renderer()->CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, 1280, 720, 1);
g_meshColorMSAA = Renderer()->CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, 1280, 720, 4);
glm_mat4_identity(g_cameraView);
};
void IVulkan::CreatePipelines()
{
for (auto &step: Renderer()->m_StepPrepass)
step.pPipeline->Init();
for (auto &step: Renderer()->m_StepMeshRendering)
step.pPipeline->Init();
for (auto &step: Renderer()->m_StepShading)
step.pPipeline->Init();
for (auto &step: Renderer()->m_StepPostProcessing)
step.pPipeline->Init();
for (auto &step: Renderer()->m_StepUI)
step.pPipeline->Init();
}
void IVulkan::Frame()
{
mat4 perspective;
glm_mat4_inv(g_cameraView, g_cameraDataMap->viewprojection);
glm_perspective(glm_rad(68),(float)g_nWindowWidth/g_nWindowHeight, 0.01, 10000, perspective);
glm_rotate(perspective, glm_rad(90), (vec4){1,0,0,0});
glm_scale(perspective, (vec4){1,-1,1,1});
glm_rotate(perspective, glm_rad(90), (vec4){0,0,1,0});
glm_mat4_mul(perspective,g_cameraDataMap->viewprojection,g_cameraDataMap->viewprojection);
s_SwapchainImage.m_image.m_image = g_swapchainImage;
s_SwapchainImage.m_image.m_imageView = g_swapchainImageView;
s_SwapchainImage.m_image.m_format = g_swapchainFormat;
s_SwapchainImage.m_usage = IMAGE_USAGE_COLOR_ATTACHMENT;
s_SwapchainImage.format = IMAGE_FORMAT_R8G8B8A8;
if (g_bConfigNotify)
{
Renderer()->DestroyImage(g_meshDepth);
Renderer()->DestroyImage(g_meshDepthMSAA);
Renderer()->DestroyImage(g_meshColor);
Renderer()->DestroyImage(g_meshColorMSAA);
g_meshDepth = Renderer()->CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 1);
g_meshDepthMSAA = Renderer()->CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 4);
g_meshColor = Renderer()->CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 1);
g_meshColorMSAA = Renderer()->CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 4);
}
for (auto &step: Renderer()->m_StepPrepass)
step.pPipeline->Frame(0);
Renderer()->Barrier(BARRIER_STAGE_TOP, BARRIER_STAGE_COLOR_OUTPUT | BARRIER_STAGE_DEPTH_OUTPUT, {}, {
{
.in = BARRIER_MEMORY_PERMISSIONS_NONE,
.out = BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE,
.pImage = g_meshColor,
},
{
.in = BARRIER_MEMORY_PERMISSIONS_NONE,
.out = BARRIER_MEMORY_PERMISSIONS_DEPTH_WRITE,
.pImage = g_meshDepth,
},
}
);
Renderer()->Begin(g_nWindowWidth, g_nWindowHeight,
{
{
g_meshColor,
0,
ATTACHMENT_LOAD_MODE_CLEAR,
ATTACHMENT_STORE_MODE_STORE,
}
},
{
g_meshDepth,
0,
ATTACHMENT_LOAD_MODE_CLEAR,
ATTACHMENT_STORE_MODE_STORE,
});
for (auto &step: Renderer()->m_StepMeshRendering)
{
step.pPipeline->Frame(0);
}
Renderer()->End();
Renderer()->Barrier(BARRIER_STAGE_DEPTH_OUTPUT, BARRIER_STAGE_BOTTOM, {}, {
{
.in = BARRIER_MEMORY_PERMISSIONS_DEPTH_WRITE,
.out = BARRIER_MEMORY_PERMISSIONS_NONE,
.pImage = g_meshDepth,
},
}
);
Renderer()->Barrier(BARRIER_STAGE_COLOR_OUTPUT, BARRIER_STAGE_BLIT, {}, {
{
.in = BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE,
.out = BARRIER_MEMORY_PERMISSIONS_COPY_READ,
.pImage = g_meshColor,
},
{
.in = BARRIER_MEMORY_PERMISSIONS_NONE,
.out = BARRIER_MEMORY_PERMISSIONS_COPY_WRITE,
.pImage = Renderer()->GetOutputImage(),
}
}
);
VkImageBlit imageCopyRegion = {};
imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.srcSubresource.mipLevel = 0;
imageCopyRegion.srcSubresource.baseArrayLayer = 0;
imageCopyRegion.srcSubresource.layerCount = 1;
imageCopyRegion.srcOffsets[0] = {0, 0, 0};
imageCopyRegion.srcOffsets[1] = {(int)g_nWindowWidth, (int)g_nWindowHeight, 1};
imageCopyRegion.dstSubresource = imageCopyRegion.srcSubresource;
imageCopyRegion.dstOffsets[0] = {0, 0, 0};
imageCopyRegion.dstOffsets[1] = {(int)g_nWindowWidth, (int)g_nWindowHeight, 1};
vkCmdBlitImage(
g_vkCommandBuffer,
((CVkImage*)g_meshColor)->m_image.m_image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
g_swapchainImage,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &imageCopyRegion,
VK_FILTER_NEAREST
);
Renderer()->Barrier(BARRIER_STAGE_BLIT, BARRIER_STAGE_COLOR_OUTPUT, {},
{
{
.in = BARRIER_MEMORY_PERMISSIONS_COPY_WRITE,
.out = BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE | BARRIER_MEMORY_PERMISSIONS_COLOR_READ,
.pImage = Renderer()->GetOutputImage(),
}
}
);
for (auto &step: Renderer()->m_StepShading)
step.pPipeline->Frame(0);
for (auto &step: Renderer()->m_StepPostProcessing)
step.pPipeline->Frame(0);
for (auto &step: Renderer()->m_StepUI)
step.pPipeline->Frame(0);
Renderer()->Barrier(BARRIER_STAGE_COLOR_OUTPUT, BARRIER_STAGE_IMAGE_OUPUT, {},
{
{
.in = BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE,
.out = 0,
.pImage = Renderer()->GetOutputImage(),
}
}
);
};
void vk_shader_t::Create( const char *szPath, VkShaderStageFlagBits shaderStage )
{
FileHandle_t shader = FileSystem()->Open(szPath, IFILE_READ);
if (!shader)
Plat_FatalErrorFunc("Failed to open shader %s\n", szPath);
CUtlBuffer<uint8_t> buffer(FileSystem()->Size(shader));
FileSystem()->Read(shader, buffer.GetMemory(), buffer.GetSize());
Create(buffer, shaderStage);
FileSystem()->Close(shader);
}
void vk_shader_t::Create( CUtlBuffer<uint8_t> &spirv, VkShaderStageFlagBits shaderStage )
{
if (m_shaderModule != NULL)
Plat_FatalErrorFunc("Shader already exists");
VkShaderModuleCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
createInfo.codeSize = spirv.GetSize();
createInfo.pCode = (uint32_t*)spirv.GetMemory();
vkCreateShaderModule(g_vkDevice, &createInfo, NULL, &m_shaderModule);
m_stageCreateInfo = {};
m_stageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
m_stageCreateInfo.module = m_shaderModule;
m_stageCreateInfo.stage = shaderStage;
m_stageCreateInfo.pName = "main";
}
void vk_shader_t::Destroy( void )
{
if (m_shaderModule == NULL)
Plat_FatalErrorFunc("Shader doesn't exist");
vkDestroyShaderModule(g_vkDevice, m_shaderModule, NULL);
}
void vk_tripipeline_t::Create(
CUtlVector<vk_shader_t> &shaders,
CUtlVector<VkDescriptorSetLayoutBinding> &bindings,
uint32_t pushConstantSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormat,
CUtlVector<VkFormat> formats
)
{
VkPushConstantRange pushConstantRange = {};
pushConstantRange.stageFlags = VK_SHADER_STAGE_ALL;
pushConstantRange.offset = 0;
pushConstantRange.size = pushConstantSize;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {};
descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCreateInfo.bindingCount = bindings.GetSize();
descriptorSetLayoutCreateInfo.pBindings = bindings.GetData();
vkCreateDescriptorSetLayout(g_vkDevice, &descriptorSetLayoutCreateInfo, NULL, &m_descriptorSetLayout);
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCreateInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.pSetLayouts = &m_descriptorSetLayout;
if (pushConstantSize != 0)
{
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
}
vkCreatePipelineLayout(g_vkDevice, &pipelineLayoutCreateInfo, NULL, &m_layout);
VkDynamicState dynamicStates[] = {
/* pInputAssemblyState */
VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE,
/* pViewportState */
VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT,
VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT,
/* pRasterizationState */
VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT,
VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE,
VK_DYNAMIC_STATE_POLYGON_MODE_EXT,
VK_DYNAMIC_STATE_CULL_MODE,
VK_DYNAMIC_STATE_FRONT_FACE,
VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE,
VK_DYNAMIC_STATE_DEPTH_BIAS,
VK_DYNAMIC_STATE_LINE_WIDTH,
/* pMultisampleState */
VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT,
VK_DYNAMIC_STATE_SAMPLE_MASK_EXT,
VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT,
/* pDepthStencilState */
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE,
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE,
VK_DYNAMIC_STATE_DEPTH_COMPARE_OP,
VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE,
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE,
VK_DYNAMIC_STATE_STENCIL_OP,
VK_DYNAMIC_STATE_DEPTH_BOUNDS,
};
VkVertexInputBindingDescription vibd = {
.binding = 0,
.stride = nVertexSize,
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
};
VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = sizeof(dynamicStates)/sizeof(VkDynamicState),
.pDynamicStates = dynamicStates,
};
CUtlVector<VkVertexInputAttributeDescription> viad(vertexFormat.GetSize());
for ( uint32_t i = 0; i < viad.GetSize(); i++ )
{
viad[i].location = vertexFormat[i].binding;
viad[i].binding = 0;
viad[i].format = IRenderer_VertexToVk(vertexFormat[i].format);
viad[i].offset = vertexFormat[i].offset;
}
VkPipelineVertexInputStateCreateInfo pvisci = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &vibd,
.vertexAttributeDescriptionCount = (uint32_t)viad.GetSize(),
.pVertexAttributeDescriptions = viad.GetData()
};
VkPipelineInputAssemblyStateCreateInfo piasci = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
.primitiveRestartEnable = VK_TRUE,
};
VkPipelineColorBlendAttachmentState pcbas = {
.blendEnable = VK_TRUE,
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.colorBlendOp = VK_BLEND_OP_ADD,
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
.alphaBlendOp = VK_BLEND_OP_ADD,
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
};
VkPipelineColorBlendStateCreateInfo pcbsci = {};
pcbsci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
pcbsci.logicOpEnable = VK_FALSE;
pcbsci.attachmentCount = 1;
pcbsci.pAttachments = &pcbas;
VkPipelineRenderingCreateInfo prci = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
.pNext = NULL,
.colorAttachmentCount = (uint32_t)formats.GetSize(),
.pColorAttachmentFormats = formats.GetData(),
.depthAttachmentFormat = VK_FORMAT_D32_SFLOAT,
};
VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo = {};
graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
graphicsPipelineCreateInfo.pVertexInputState = &pvisci;
graphicsPipelineCreateInfo.pInputAssemblyState = &piasci;
graphicsPipelineCreateInfo.pColorBlendState = &pcbsci;
graphicsPipelineCreateInfo.pDynamicState = &pipelineDynamicStateCreateInfo;
graphicsPipelineCreateInfo.layout = m_layout;
graphicsPipelineCreateInfo.stageCount = shaders.GetSize();
CUtlVector<VkPipelineShaderStageCreateInfo> stages(graphicsPipelineCreateInfo.stageCount);
uint32_t i = 0;
for (auto &shader: shaders)
{
stages[i] = shader.m_stageCreateInfo;
i++;
}
graphicsPipelineCreateInfo.pStages = stages.GetData();
graphicsPipelineCreateInfo.pNext = &prci;
vkCreateGraphicsPipelines(g_vkDevice, NULL, 1, &graphicsPipelineCreateInfo, NULL, &m_pipeline);
}
void vk_tripipeline_t::Destroy()
{
}
void vk_comppipeline_t::Create(
vk_shader_t &shader,
CUtlVector<VkDescriptorSetLayoutBinding> &bindings,
uint32_t pushConstantsSize
)
{
VkPushConstantRange pushConstantRange = {};
pushConstantRange.stageFlags = VK_SHADER_STAGE_ALL;
pushConstantRange.offset = 0;
pushConstantRange.size = pushConstantsSize;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {};
descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCreateInfo.bindingCount = bindings.GetSize();
descriptorSetLayoutCreateInfo.pBindings = bindings.GetData();
vkCreateDescriptorSetLayout(g_vkDevice, &descriptorSetLayoutCreateInfo, NULL, &m_descriptorSetLayout);
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCreateInfo.setLayoutCount = 1;
pipelineLayoutCreateInfo.pSetLayouts = &m_descriptorSetLayout;
if (pushConstantsSize != 0)
{
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
}
vkCreatePipelineLayout(g_vkDevice, &pipelineLayoutCreateInfo, NULL, &m_layout);
VkComputePipelineCreateInfo cpci = {};
cpci.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
cpci.stage = shader.m_stageCreateInfo;
cpci.layout = m_layout;
vkCreateComputePipelines(g_vkDevice, NULL, 1, &cpci, NULL, &m_pipeline);
}
void vk_comppipeline_t::Destroy()
{
}
void vk_buffer_t::Create(size_t size, VkBufferUsageFlags usage)
{
VkBufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferCreateInfo.usage = usage;
bufferCreateInfo.size = size;
VmaAllocationCreateInfo allocInfo = {};
allocInfo.usage = VMA_MEMORY_USAGE_AUTO;
allocInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
VMA_ALLOCATION_CREATE_MAPPED_BIT;
m_nSize = size;
vmaCreateBuffer(g_allocator, &bufferCreateInfo, &allocInfo, &m_buffer, &m_memory, NULL);
}
void vk_buffer_t::Destroy()
{
}
void *vk_buffer_t::Map(size_t offset, size_t size)
{
void *pData;
vmaMapMemory(g_allocator, m_memory, &pData);
return pData;
}
void vk_buffer_t::Unmap()
{
vmaUnmapMemory(g_allocator, m_memory);
}
void vk_buffer_t::CopyTo(struct vk_image2d_t *image)
{
}
void vk_buffer_t::CopyTo(struct vk_buffer_t *buffer)
{
}
void vk_image2d_t::Create(size_t x, size_t y, VkFormat format, VkImageUsageFlags usage, VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT)
{
VkImageCreateInfo imageInfo={};
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.extent.width = x > 1 ? x : 1;
imageInfo.extent.height = y > 1 ? y : 1;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.usage = usage;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.format=format;
imageInfo.samples = samples;
VmaAllocationCreateInfo alloc = {};
alloc.usage=VMA_MEMORY_USAGE_AUTO;
vmaCreateImage(g_allocator, &imageInfo,&alloc, &m_image, &m_memory,0);
m_X=imageInfo.extent.width;
m_Y=imageInfo.extent.width;
m_format=format;
VkImageView imageView = 0;
VkImageViewCreateInfo imageViewCreateInfo={};
imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCreateInfo.format = format;
imageViewCreateInfo.image = m_image;
imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
if (format == VK_FORMAT_D32_SFLOAT) {
imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
}
imageViewCreateInfo.subresourceRange.baseMipLevel = 0;
imageViewCreateInfo.subresourceRange.levelCount = 1;
imageViewCreateInfo.subresourceRange.baseArrayLayer = 0;
imageViewCreateInfo.subresourceRange.layerCount = 1;
vkCreateImageView(g_vkDevice, &imageViewCreateInfo, 0, &m_imageView);
}
void vk_image2d_t::Destroy()
{
vkDestroyImageView(g_vkDevice, m_imageView, NULL);
vmaDestroyImage(g_allocator, m_image, NULL);
}
void CopyTo(struct vk_image2d_t *image);
void CopyTo(struct vk_buffer_t *buffer);
void *CVkBuffer::Map()
{
if (!m_pAllocated)
m_pAllocated = m_buffer.Map(0, m_buffer.m_nSize);
return m_pAllocated;
};
void CVkBuffer::Unmap()
{
if (!m_pAllocated)
return;
m_buffer.Unmap();
m_pAllocated = 0;
};
CUtlVector<ITexture*> g_textures;
CUtlVector<ITexture*> g_newtextures;
uint32_t ITextureManager::GetTextureID(ITexture *pTexture)
{
uint32_t i = 0;
for (auto &t: g_textures)
{
if (pTexture == t)
return i;
i++;
}
return 0;
}
ITexture *ITextureManager::LoadTexture( void *pData, uint32_t X, uint32_t Y, uint32_t numChannels )
{
CVkTexture *pTexture = new CVkTexture;
*pTexture = {};
pTexture->x = X;
pTexture->y = Y;
VkDeviceSize imageSize = X*Y*4;
vk_buffer_t gpu_buffer = {};
gpu_buffer.Create(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
void *gpu_buffer_map = gpu_buffer.Map(0, 0);
V_memcpy(gpu_buffer_map, pData, imageSize);
gpu_buffer.Unmap();
pTexture->image = {};
pTexture->image.Create(X, Y, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
VkCommandPool commandPool;
VkCommandBuffer commandBuffer;
VkCommandPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.queueFamilyIndex = g_drawfamily;
poolInfo.flags = 0;
vkCreateCommandPool(g_vkDevice, &poolInfo, NULL, &commandPool);
VkCommandBufferAllocateInfo cmdAllocInfo{};
cmdAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmdAllocInfo.commandPool = commandPool;
cmdAllocInfo.commandBufferCount = 1;
vkAllocateCommandBuffers(g_vkDevice, &cmdAllocInfo, &commandBuffer);
VkCommandBufferBeginInfo beginInfo{};
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
vkBeginCommandBuffer(commandBuffer, &beginInfo);
VkImageMemoryBarrier barrier{};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = pTexture->image.m_image;
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
barrier.subresourceRange.baseMipLevel = 0;
barrier.subresourceRange.levelCount = 1;
barrier.subresourceRange.baseArrayLayer = 0;
barrier.subresourceRange.layerCount = 1;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
VkBufferImageCopy region{};
region.bufferOffset = 0;
region.bufferRowLength = 0;
region.bufferImageHeight = 0;
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.mipLevel = 0;
region.imageSubresource.baseArrayLayer = 0;
region.imageSubresource.layerCount = 1;
region.imageOffset = {0, 0, 0};
region.imageExtent = {(uint32_t)X, (uint32_t)Y, 1};
vkCmdCopyBufferToImage(
commandBuffer,
gpu_buffer.m_buffer,
pTexture->image.m_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&region
);
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, NULL,
0, NULL,
1, &barrier
);
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(g_drawQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(g_drawQueue);
vkFreeCommandBuffers(g_vkDevice, commandPool, 1, &commandBuffer);
vkDestroyCommandPool(g_vkDevice, commandPool, NULL);
g_newtextures.AppendTail(pTexture);
g_textures.AppendTail(pTexture);
return pTexture;
};
ITexture *ITextureManager::LoadTexture( const char *szName )
{
for (ITexture *texture: g_textures)
{
if (!texture->szName)
continue;
if (!V_strcmp(texture->szName, szName))
return texture;
};
FileHandle_t file = FileSystem()->Open(szName, IFILE_READ);
if (!file)
Plat_FatalErrorFunc("Failed to load %s\n", szName);
CUtlBuffer<stbi_uc> buffer(FileSystem()->Size(file));
FileSystem()->Read(file, buffer.GetMemory(), buffer.GetSize());
int nImageX;
int nImageY;
int nImageChannels;
stbi_uc *pixels = stbi_load_from_memory((stbi_uc*)buffer.GetMemory(), buffer.GetSize(), &nImageX, &nImageY, &nImageChannels, STBI_rgb_alpha);
ITexture *pTexture = ITextureManager::LoadTexture(pixels, nImageX, nImageY, 4);
pTexture->szName = szName;
return pTexture;
};
interface CVkRenderer: public IRenderer
{
public:
virtual void Init() override {};
virtual void Frame() override {};
virtual void Deinit() override {};
virtual IStorageBuffer *CreateStorageBuffer( uint32_t uSize ) override;
virtual IUniformBuffer *CreateUniformBuffer( uint32_t uSize ) override;
virtual IVertexBuffer *CreateVertexBuffer( uint32_t uSize ) override;
virtual IIndexBuffer *CreateIndexBuffer( uint32_t uSize ) override;
virtual IImage *CreateImage( EImageFormat format, uint32_t usage, uint32_t nWidth, uint32_t nHeight, uint32_t nSamples = 1 ) override;
virtual void DestroyBuffer( IBuffer *pBuffer ) override;
virtual void DestroyImage( IImage *pImage ) override;
virtual void SetConstants( uint32_t nSize, void *pData ) override;
virtual void Barrier( uint32_t stageIn, uint32_t stageOut, CUtlVector<BufferBarrier_t> buffers, CUtlVector<ImageBarrier_t> images ) override;
virtual void BindPipeline( IPipeline *pPipeline ) override;
virtual void Begin( uint32_t nWidth, uint32_t nHeight, CUtlVector<RenderingColorAttachment_t> attachments, RenderingDepthAttachment_t depth ) override;
virtual void ResetState() override;
virtual void SetDepthMode( EDepthMode mode ) override;
virtual void Draw( IVertexBuffer *pVertex, IIndexBuffer *pIndex ) override;
virtual void End() override;
virtual void Dispatch( uint32_t x, uint32_t y, uint32_t z ) override;
virtual void TraceRays( uint32_t x, uint32_t y, uint32_t z ) override;
virtual IGraphicsPipeline *CreateGraphicsPipeline(
CUtlVector<Shader_t> shaders,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormat,
CUtlVector<EImageFormat> outputFormats,
bool bDepth
) override;
virtual IComputePipeline *CreateComputePipeline(
Shader_t szShader,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize
) override;
virtual IRayTracingPipeline *CreateRayTracingPipeline(
CUtlVector<Shader_t> shaders,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize
) override;
virtual IBuffer *GetCameraMatrix() override;
virtual IImage *GetOutputImage() override;
};
DECLARE_ENGINE_INTERFACE(Renderer, CVkRenderer)
IStorageBuffer *CVkRenderer::CreateStorageBuffer( uint32_t uSize )
{
CVkBuffer *pBuffer = new CVkBuffer();
pBuffer->m_buffer.Create(uSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
return pBuffer;
}
IUniformBuffer *CVkRenderer::CreateUniformBuffer( uint32_t uSize )
{
CVkBuffer *pBuffer = new CVkBuffer();
pBuffer->m_buffer.Create(uSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT);
return pBuffer;
}
IVertexBuffer *CVkRenderer::CreateVertexBuffer( uint32_t uSize )
{
CVkBuffer *pBuffer = new CVkBuffer();
pBuffer->m_buffer.Create(uSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
return pBuffer;
}
IIndexBuffer *CVkRenderer::CreateIndexBuffer( uint32_t uSize )
{
CVkBuffer *pBuffer = new CVkBuffer();
pBuffer->m_buffer.Create(uSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT);
return pBuffer;
}
IImage *CVkRenderer::CreateImage( EImageFormat format, uint32_t usage, uint32_t nWidth, uint32_t nHeight, uint32_t nSamples )
{
VkFormat vkformat;
VkImageUsageFlags vkusage = 0;
CVkImage *pImage = new CVkImage();
VkSampleCountFlagBits samples;
switch (format)
{
case IMAGE_FORMAT_R8G8B8A8: vkformat = VK_FORMAT_R8G8B8A8_UNORM; break;
case IMAGE_FORMAT_R16G16B16A16: vkformat = VK_FORMAT_R16G16B16A16_UNORM; break;
case IMAGE_FORMAT_DEPTH: vkformat = VK_FORMAT_D32_SFLOAT; break;
default: return 0;
};
if (usage&IMAGE_USAGE_COLOR_ATTACHMENT) vkusage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
if (usage&IMAGE_USAGE_DEPTH_ATTACHMENT) vkusage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
if (usage&IMAGE_USAGE_STORAGE) vkusage |= VK_IMAGE_USAGE_STORAGE_BIT;
vkusage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
vkusage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
switch (nSamples)
{
case 1: samples = VK_SAMPLE_COUNT_1_BIT; break;
case 4: samples = VK_SAMPLE_COUNT_4_BIT; break;
default: samples = VK_SAMPLE_COUNT_1_BIT; break;
}
pImage->m_usage = usage;
pImage->m_image = {};
pImage->format = format;
pImage->m_image.Create(nWidth, nHeight, vkformat, vkusage, samples);
return pImage;
};
void CVkRenderer::DestroyBuffer( IBuffer *pBuffer )
{
CVkBuffer *pVkBuffer = (CVkBuffer*)pBuffer;
if (pVkBuffer)
pVkBuffer->m_buffer.Destroy();
}
void CVkRenderer::DestroyImage( IImage *pImage )
{
CVkImage *pVkImage = (CVkImage*)pImage;
if (pVkImage)
pVkImage->m_image.Destroy();
}
IPipeline *g_pCurrentPipeline;
void CVkRenderer::SetConstants( uint32_t nSize, void *pData )
{
if (!g_pCurrentPipeline)
return;
if (g_pCurrentPipeline->type == PIPELINE_TYPE_RASTERIZATION)
{
CVkGraphicsPipeline *pVkPipeline = (CVkGraphicsPipeline*)g_pCurrentPipeline;
vkCmdPushConstants(g_vkCommandBuffer, pVkPipeline->m_pipeline.m_layout, VK_SHADER_STAGE_ALL, 0, nSize, pData);
}
}
void CVkRenderer::Barrier( uint32_t stageIn, uint32_t stageOut, CUtlVector<BufferBarrier_t> buffers, CUtlVector<ImageBarrier_t> images )
{
VkPipelineStageFlags psfSrc = 0;
VkPipelineStageFlags psfDst = 0;
if (stageIn & BARRIER_STAGE_TOP) psfSrc |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
if (stageIn & BARRIER_STAGE_VERTEX_INPUT) psfSrc |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
if (stageIn & BARRIER_STAGE_VERTEX_SHADER) psfSrc |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
if (stageIn & BARRIER_STAGE_GEOMETRY_SHADER) psfSrc |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
if (stageIn & BARRIER_STAGE_FRAGMENT_SHADER) psfSrc |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
if (stageIn & BARRIER_STAGE_COLOR_OUTPUT) psfSrc |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
if (stageIn & BARRIER_STAGE_DEPTH_OUTPUT) psfSrc |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
if (stageIn & BARRIER_STAGE_RAY_TRACING_SHADER) psfSrc |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
if (stageIn & BARRIER_STAGE_BLIT) psfSrc |= VK_PIPELINE_STAGE_TRANSFER_BIT;
if (stageIn & BARRIER_STAGE_COPY) psfSrc |= VK_PIPELINE_STAGE_TRANSFER_BIT;
if (stageOut & BARRIER_STAGE_TOP) psfDst |= VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
if (stageOut & BARRIER_STAGE_VERTEX_INPUT) psfDst |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
if (stageOut & BARRIER_STAGE_VERTEX_SHADER) psfDst |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
if (stageOut & BARRIER_STAGE_GEOMETRY_SHADER) psfDst |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
if (stageOut & BARRIER_STAGE_FRAGMENT_SHADER) psfDst |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
if (stageOut & BARRIER_STAGE_COLOR_OUTPUT) psfDst |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
if (stageOut & BARRIER_STAGE_DEPTH_OUTPUT) psfDst |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
if (stageOut & BARRIER_STAGE_RAY_TRACING_SHADER) psfDst |= VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
if (stageOut & BARRIER_STAGE_BOTTOM) psfDst |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
if (stageOut & BARRIER_STAGE_BLIT) psfDst |= VK_PIPELINE_STAGE_TRANSFER_BIT;
if (stageOut & BARRIER_STAGE_IMAGE_OUPUT) psfDst |= VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
CUtlVector<VkImageMemoryBarrier> imb = {};
CUtlVector<VkBufferMemoryBarrier> bmb = {};
for (auto &buffer: buffers)
{
CVkBuffer *pVkBuffer = (CVkBuffer*)buffer.pBuffer;
VkBufferMemoryBarrier b = {};
b.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
b.buffer = pVkBuffer->m_buffer.m_buffer;
b.size = pVkBuffer->m_buffer.m_nSize;
b.srcQueueFamilyIndex = g_drawfamily;
b.dstQueueFamilyIndex = g_drawfamily;
switch (buffer.in)
{
case BARRIER_MEMORY_PERMISSIONS_COLOR_READ: b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; break;
case BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE: b.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; break;
default:
break;
};
switch (buffer.out)
{
case BARRIER_MEMORY_PERMISSIONS_COLOR_READ: b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; break;
case BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE: b.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; break;
default:
break;
};
bmb.AppendTail(b);
}
for (auto &image: images)
{
CVkImage *pVkImage = (CVkImage*)image.pImage;
VkImageMemoryBarrier b = {};
b.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
b.image = pVkImage->m_image.m_image;
VkImageSubresourceRange isr = {
.aspectMask = (pVkImage->format == IMAGE_FORMAT_DEPTH) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
.layerCount = 1,
};
b.subresourceRange = isr;
b.oldLayout = pVkImage->m_currentLayout;
if (pVkImage->m_usage == IMAGE_USAGE_COLOR_ATTACHMENT)
{
b.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
if (pVkImage->m_usage == IMAGE_USAGE_DEPTH_ATTACHMENT)
{
b.newLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
}
b.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
if (image.in & BARRIER_MEMORY_PERMISSIONS_COLOR_READ) b.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE) b.srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_DEPTH_READ) b.srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_DEPTH_WRITE) b.srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_COPY_READ) b.srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_COPY_WRITE) b.srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_BLIT_READ) b.srcAccessMask |= VK_ACCESS_TRANSFER_READ_BIT;
if (image.in & BARRIER_MEMORY_PERMISSIONS_BLIT_WRITE) b.srcAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT;
if (image.out & BARRIER_MEMORY_PERMISSIONS_COLOR_READ) b.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
if (image.out & BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE) b.dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
if (image.out & BARRIER_MEMORY_PERMISSIONS_DEPTH_READ) b.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
if (image.out & BARRIER_MEMORY_PERMISSIONS_DEPTH_WRITE) b.dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
if (image.out & BARRIER_MEMORY_PERMISSIONS_COPY_READ) { b.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; }
if (image.out & BARRIER_MEMORY_PERMISSIONS_COPY_WRITE) { b.dstAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; }
if (image.out & BARRIER_MEMORY_PERMISSIONS_BLIT_READ) { b.dstAccessMask |= VK_ACCESS_TRANSFER_READ_BIT; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; }
if (image.out & BARRIER_MEMORY_PERMISSIONS_BLIT_WRITE) { b.dstAccessMask |= VK_ACCESS_TRANSFER_WRITE_BIT; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; }
if (stageOut & BARRIER_STAGE_IMAGE_OUPUT) b.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
pVkImage->m_currentLayout = b.newLayout;
imb.AppendTail(b);
}
vkCmdPipelineBarrier(g_vkCommandBuffer, psfSrc, psfDst, 0, 0, 0, bmb.GetSize(), bmb.GetData(), imb.GetSize(), imb.GetData());
}
void CVkRenderer::BindPipeline( IPipeline *pPipeline )
{
if (!pPipeline)
return;
if (pPipeline->type == PIPELINE_TYPE_RASTERIZATION)
{
CVkGraphicsPipeline *pVkPipeline = (CVkGraphicsPipeline*)pPipeline;
vkCmdBindPipeline(g_vkCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pVkPipeline->m_pipeline.m_pipeline);
vkCmdBindDescriptorSets(g_vkCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pVkPipeline->m_pipeline.m_layout, 0, 1, &pVkPipeline->m_descriptorSet, 0, NULL);
}
g_pCurrentPipeline = pPipeline;
}
void CVkRenderer::Begin( uint32_t nWidth, uint32_t nHeight, CUtlVector<RenderingColorAttachment_t> attachments, RenderingDepthAttachment_t depth )
{
CUtlVector<VkRenderingAttachmentInfo> colorAttachments = {};
VkRenderingAttachmentInfo depthAttachment = {};
for (auto &attachment: attachments)
{
VkRenderingAttachmentInfo vkattachment = {};
vkattachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
CVkImage *pImage = (CVkImage*)attachment.pOutput;
CVkImage *pTemporary = (CVkImage*)attachment.pTemporary;
if (attachment.pTemporary)
{
vkattachment.imageView = pTemporary->m_image.m_imageView;
vkattachment.resolveImageView = pImage->m_image.m_imageView;
vkattachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
vkattachment.resolveImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
} else
{
vkattachment.imageView = pImage->m_image.m_imageView;
vkattachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
vkattachment.loadOp = IRenderer_LoadOpVk(attachment.loadMode);
vkattachment.storeOp = IRenderer_StoreOpVk(attachment.storeMode);
colorAttachments.AppendTail(vkattachment);
}
depthAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO;
CVkImage *pDepthImage = (CVkImage*)depth.pOutput;
CVkImage *pDepthTemporary = (CVkImage*)depth.pTemporary;
if (!depth.pOutput)
goto skip_depth;
if (depth.pTemporary)
{
depthAttachment.imageView = pDepthTemporary->m_image.m_imageView;
depthAttachment.resolveImageView = pDepthImage->m_image.m_imageView;
depthAttachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
depthAttachment.resolveImageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
} else
{
depthAttachment.imageView = pDepthImage->m_image.m_imageView;
depthAttachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL;
}
depthAttachment.loadOp = IRenderer_LoadOpVk(depth.loadMode);
depthAttachment.storeOp = IRenderer_StoreOpVk(depth.storeMode);
depthAttachment.clearValue = (VkClearValue){.depthStencil = {.depth = 1}};
skip_depth:
VkRenderingInfo renderInfo = {
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO,
.renderArea = {{0, 0}, {nWidth, nHeight}},
.layerCount = 1,
.colorAttachmentCount = (uint32_t)colorAttachments.GetSize(),
.pColorAttachments = colorAttachments.GetData(),
.pDepthAttachment = depth.pOutput ? &depthAttachment : 0,
};
vkCmdBeginRendering(g_vkCommandBuffer, &renderInfo);
}
void CVkRenderer::ResetState()
{
vkCmdSetRasterizerDiscardEnable(g_vkCommandBuffer, VK_FALSE);
vkCmdSetDepthBiasEnable(g_vkCommandBuffer, VK_FALSE);
vkCmdSetCullMode(g_vkCommandBuffer, VK_CULL_MODE_BACK_BIT);
vkCmdSetFrontFace(g_vkCommandBuffer, VK_FRONT_FACE_COUNTER_CLOCKWISE);
vkCmdSetDepthTestEnable(g_vkCommandBuffer, VK_FALSE);
vkCmdSetDepthWriteEnable(g_vkCommandBuffer, VK_FALSE);
_vkCmdSetPolygonModeEXT(g_vkCommandBuffer, VK_POLYGON_MODE_FILL);
_vkCmdSetRasterizationSamplesEXT(g_vkCommandBuffer, VK_SAMPLE_COUNT_1_BIT);
VkSampleMask sampleMask = 0xFFFFFFFF;
_vkCmdSetSampleMaskEXT(g_vkCommandBuffer, VK_SAMPLE_COUNT_1_BIT, &sampleMask);
_vkCmdSetAlphaToCoverageEnableEXT(g_vkCommandBuffer, VK_FALSE);
VkViewport viewport = {0, 0, (float)g_nWindowWidth, (float)g_nWindowHeight, 0.0f, 1.0f};
VkRect2D scissor = {{0, 0}, {g_nWindowWidth, g_nWindowHeight}};
vkCmdSetViewportWithCount(g_vkCommandBuffer, 1, &viewport);
vkCmdSetScissorWithCount(g_vkCommandBuffer, 1, &scissor);
vkCmdSetPrimitiveTopology(g_vkCommandBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
vkCmdSetPrimitiveRestartEnable(g_vkCommandBuffer, VK_FALSE);
}
void CVkRenderer::SetDepthMode( EDepthMode mode )
{
if (mode == DEPTH_MODE_DISABLED)
{
vkCmdSetDepthTestEnable(g_vkCommandBuffer, VK_FALSE);
vkCmdSetDepthWriteEnable(g_vkCommandBuffer, VK_FALSE);
return;
}
vkCmdSetDepthTestEnable(g_vkCommandBuffer, VK_TRUE);
vkCmdSetDepthWriteEnable(g_vkCommandBuffer, VK_TRUE);
vkCmdSetDepthCompareOp(g_vkCommandBuffer, VK_COMPARE_OP_LESS);
vkCmdSetStencilTestEnable(g_vkCommandBuffer, VK_FALSE);
}
void CVkRenderer::Draw( IVertexBuffer *pVertex, IIndexBuffer *pIndex )
{
CVkBuffer *pVkVertex = (CVkBuffer*)pVertex;
CVkBuffer *pVkIndex = (CVkBuffer*)pIndex;
if (!g_pCurrentPipeline)
return;
if (g_pCurrentPipeline->type == PIPELINE_TYPE_RASTERIZATION)
{
CVkGraphicsPipeline *pVkPipeline = (CVkGraphicsPipeline*)g_pCurrentPipeline;
VkDeviceSize offset = 0;
vkCmdBindVertexBuffers(g_vkCommandBuffer, 0, 1, &pVkVertex->m_buffer.m_buffer, &offset);
if (pVkIndex)
{
vkCmdBindIndexBuffer(
g_vkCommandBuffer,
pVkIndex->m_buffer.m_buffer,
0,
VK_INDEX_TYPE_UINT32
);
vkCmdDrawIndexed(g_vkCommandBuffer, pVkIndex->m_buffer.m_nSize/4, 1, 0, 0, 0);
}
else
{
vkCmdDraw(g_vkCommandBuffer, pVkVertex->m_buffer.m_nSize/pVkPipeline->nVertexSize,1,0,0);
}
}
}
void CVkRenderer::Dispatch( uint32_t x, uint32_t y, uint32_t z )
{
}
void CVkRenderer::TraceRays( uint32_t x, uint32_t y, uint32_t z )
{
}
void CVkRenderer::End()
{
vkCmdEndRendering(g_vkCommandBuffer);
}
IGraphicsPipeline *CVkRenderer::CreateGraphicsPipeline(
CUtlVector<Shader_t> shaders,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize,
uint32_t nVertexSize,
CUtlVector<VertexAttribute_t> vertexFormats,
CUtlVector<EImageFormat> outputFormats,
bool bDepth
)
{
CVkGraphicsPipeline *pipeline = new CVkGraphicsPipeline;
pipeline->type = PIPELINE_TYPE_RASTERIZATION;
CUtlVector<vk_shader_t> vkshaders(shaders.GetSize());
CUtlVector<VkDescriptorSetLayoutBinding> vkbindings(inputs.GetSize());
CUtlVector<VkFormat> vkformats(outputFormats.GetSize());
CUtlVector<VkVertexInputAttributeDescription> vkVertexFormats(vertexFormats.GetSize());
for ( uint32_t i = 0; i < vkshaders.GetSize(); i++ )
{
VkShaderStageFlagBits flags;
if (shaders[i].type == SHADER_TYPE_VERTEX) flags = VK_SHADER_STAGE_VERTEX_BIT;
if (shaders[i].type == SHADER_TYPE_FRAGMENT) flags = VK_SHADER_STAGE_FRAGMENT_BIT;
vkshaders[i].Create(shaders[i].szPath, flags);
}
for ( uint32_t i = 0; i < vkbindings.GetSize(); i++ )
{
vkbindings[i].binding = inputs[i].binding;
vkbindings[i].descriptorCount = 1;
vkbindings[i].stageFlags = VK_SHADER_STAGE_ALL;
if (inputs[i].type == SHADER_INPUT_TYPE_IMAGE) vkbindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
if (inputs[i].type == SHADER_INPUT_TYPE_UNIFORM_BUFFER) vkbindings[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
if (inputs[i].type == SHADER_INPUT_TYPE_STORAGE_BUFFER) vkbindings[i].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
if (inputs[i].type == SHADER_INPUT_TYPE_TLAS) vkbindings[i].descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
if (inputs[i].type == SHADER_INPUT_TYPE_TEXTURES)
{
vkbindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
vkbindings[i].descriptorCount = 1024;
}
}
for ( uint32_t i = 0; i < vkformats.GetSize(); i++ )
{
vkformats[i] = IRenderer_FormatToVk(outputFormats[i]);
}
pipeline->m_pipeline.Create(vkshaders, vkbindings, nConstantsSize, nVertexSize, vertexFormats, vkformats);
pipeline->nVertexSize = nVertexSize;
CUtlVector<VkDescriptorPoolSize> pools = {};
for (auto &binding: vkbindings)
{
VkDescriptorPoolSize dps = {};
dps.type = binding.descriptorType;
dps.descriptorCount = binding.descriptorCount;
pools.AppendTail(dps);
}
VkDescriptorPoolCreateInfo poolInfo = {};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = pools.GetSize();
poolInfo.pPoolSizes = pools.GetData();
poolInfo.maxSets = 1;
vkCreateDescriptorPool(g_vkDevice, &poolInfo, NULL, &pipeline->m_descriptorPool);
VkDescriptorSetAllocateInfo allocInfo = {};
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
allocInfo.descriptorPool = pipeline->m_descriptorPool;
allocInfo.descriptorSetCount = 1;
allocInfo.pSetLayouts = &pipeline->m_pipeline.m_descriptorSetLayout;
vkAllocateDescriptorSets(g_vkDevice, &allocInfo, &pipeline->m_descriptorSet);
V_printf("Created %p\n",pipeline->m_descriptorSet);
pipeline->m_writes = {};
for (auto &input: inputs)
{
VkWriteDescriptorSet write = {};
write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write.dstSet = pipeline->m_descriptorSet;
write.dstArrayElement = 0;
write.dstBinding = input.binding;
write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
if (input.type == SHADER_INPUT_TYPE_IMAGE) write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
if (input.type == SHADER_INPUT_TYPE_UNIFORM_BUFFER) write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
if (input.type == SHADER_INPUT_TYPE_STORAGE_BUFFER) write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
if (input.type == SHADER_INPUT_TYPE_TLAS) write.descriptorType = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR;
if (input.type == SHADER_INPUT_TYPE_TEXTURES)
{
write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
write.descriptorCount = 1024;
} else
write.descriptorCount = 1;
pipeline->m_writes.AppendTail(write);
}
pipeline->m_inputs = inputs;
return pipeline;
};
IComputePipeline *CVkRenderer::CreateComputePipeline(
Shader_t szShader,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize
)
{
}
IRayTracingPipeline *CVkRenderer::CreateRayTracingPipeline(
CUtlVector<Shader_t> shaders,
CUtlVector<ShaderInput_t> inputs,
uint32_t nConstantsSize
)
{
}
IBuffer *CVkRenderer::GetCameraMatrix()
{
return g_cameraProperties;
}
IImage *CVkRenderer::GetOutputImage()
{
return &s_SwapchainImage;
}