#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 m_writes; VkDescriptorPool m_descriptorPool; VkDescriptorSet m_descriptorSet; CUtlVector 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 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 = IRenderer::CreateUniformBuffer(sizeof(CameraProjection)); g_cameraDataMap = (CameraProjection*)g_cameraProperties->Map(); g_meshDepth = IRenderer::CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, 1280, 720, 1); g_meshDepthMSAA = IRenderer::CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, 1280, 720, 4); g_meshColor = IRenderer::CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, 1280, 720, 1); g_meshColorMSAA = IRenderer::CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, 1280, 720, 4); glm_mat4_identity(g_cameraView); }; void IVulkan::CreatePipelines() { for (auto &step: g_StepPrepass) step.pPipeline->Init(); for (auto &step: g_StepMeshRendering) step.pPipeline->Init(); for (auto &step: g_StepShading) step.pPipeline->Init(); for (auto &step: g_StepPostProcessing) step.pPipeline->Init(); for (auto &step: g_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) { IRenderer::DestroyImage(g_meshDepth); IRenderer::DestroyImage(g_meshDepthMSAA); IRenderer::DestroyImage(g_meshColor); IRenderer::DestroyImage(g_meshColorMSAA); g_meshDepth = IRenderer::CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 1); g_meshDepthMSAA = IRenderer::CreateImage(IMAGE_FORMAT_DEPTH, IMAGE_USAGE_DEPTH_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 4); g_meshColor = IRenderer::CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 1); g_meshColorMSAA = IRenderer::CreateImage(IMAGE_FORMAT_R8G8B8A8, IMAGE_USAGE_COLOR_ATTACHMENT, g_nWindowWidth, g_nWindowHeight, 4); } for (auto &step: g_StepPrepass) step.pPipeline->Frame(0); IRenderer::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, }, } ); IRenderer::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: g_StepMeshRendering) { step.pPipeline->Frame(0); } IRenderer::End(); IRenderer::Barrier(BARRIER_STAGE_DEPTH_OUTPUT, BARRIER_STAGE_BOTTOM, {}, { { .in = BARRIER_MEMORY_PERMISSIONS_DEPTH_WRITE, .out = BARRIER_MEMORY_PERMISSIONS_NONE, .pImage = g_meshDepth, }, } ); IRenderer::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 = IRenderer::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 ); IRenderer::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 = IRenderer::GetOutputImage(), } } ); for (auto &step: g_StepShading) step.pPipeline->Frame(0); for (auto &step: g_StepPostProcessing) step.pPipeline->Frame(0); for (auto &step: g_StepUI) step.pPipeline->Frame(0); IRenderer::Barrier(BARRIER_STAGE_COLOR_OUTPUT, BARRIER_STAGE_IMAGE_OUPUT, {}, { { .in = BARRIER_MEMORY_PERMISSIONS_COLOR_WRITE, .out = 0, .pImage = IRenderer::GetOutputImage(), } } ); }; void vk_shader_t::Create( const char *szPath, VkShaderStageFlagBits shaderStage ) { FileHandle_t shader = IFileSystem::Open(szPath, IFILE_READ); if (!shader) Plat_FatalErrorFunc("Failed to open shader %s\n", szPath); CUtlBuffer buffer(IFileSystem::Size(shader)); IFileSystem::Read(shader, buffer.GetMemory(), buffer.GetSize()); Create(buffer, shaderStage); IFileSystem::Close(shader); } void vk_shader_t::Create( CUtlBuffer &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 &shaders, CUtlVector &bindings, uint32_t pushConstantSize, uint32_t nVertexSize, CUtlVector vertexFormat, CUtlVector 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 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 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 &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 g_textures; CUtlVector 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, ®ion ); 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 = IFileSystem::Open(szName, IFILE_READ); if (!file) Plat_FatalErrorFunc("Failed to load %s\n", szName); CUtlBuffer buffer(IFileSystem::Size(file)); IFileSystem::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; }; IStorageBuffer *IRenderer::CreateStorageBuffer( uint32_t uSize ) { CVkBuffer *pBuffer = new CVkBuffer(); pBuffer->m_buffer.Create(uSize, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); return pBuffer; } IUniformBuffer *IRenderer::CreateUniformBuffer( uint32_t uSize ) { CVkBuffer *pBuffer = new CVkBuffer(); pBuffer->m_buffer.Create(uSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); return pBuffer; } IVertexBuffer *IRenderer::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 *IRenderer::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 *IRenderer::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 IRenderer::DestroyBuffer( IBuffer *pBuffer ) { CVkBuffer *pVkBuffer = (CVkBuffer*)pBuffer; if (pVkBuffer) pVkBuffer->m_buffer.Destroy(); } void IRenderer::DestroyImage( IImage *pImage ) { CVkImage *pVkImage = (CVkImage*)pImage; if (pVkImage) pVkImage->m_image.Destroy(); } IPipeline *g_pCurrentPipeline; void IRenderer::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 IRenderer::Barrier( uint32_t stageIn, uint32_t stageOut, CUtlVector buffers, CUtlVector 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 imb = {}; CUtlVector 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 IRenderer::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 IRenderer::Begin( uint32_t nWidth, uint32_t nHeight, CUtlVector attachments, RenderingDepthAttachment_t depth ) { CUtlVector 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 IRenderer::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 IRenderer::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 IRenderer::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 IRenderer::End() { vkCmdEndRendering(g_vkCommandBuffer); } IGraphicsPipeline *IRenderer::CreateGraphicsPipeline( CUtlVector shaders, CUtlVector inputs, uint32_t nConstantsSize, uint32_t nVertexSize, CUtlVector vertexFormats, CUtlVector outputFormats, bool bDepth ) { CVkGraphicsPipeline *pipeline = new CVkGraphicsPipeline; pipeline->type = PIPELINE_TYPE_RASTERIZATION; CUtlVector vkshaders(shaders.GetSize()); CUtlVector vkbindings(inputs.GetSize()); CUtlVector vkformats(outputFormats.GetSize()); CUtlVector 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 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; }; IBuffer *IRenderer::GetCameraMatrix() { return g_cameraProperties; } IImage *IRenderer::GetOutputImage() { return &s_SwapchainImage; }