2021-02-10 19:33:44 +01:00
|
|
|
#include "vk_render.h"
|
|
|
|
|
|
|
|
#include "vk_core.h"
|
|
|
|
#include "vk_buffer.h"
|
2022-05-04 18:23:37 +02:00
|
|
|
#include "vk_staging.h"
|
2021-02-10 19:33:44 +01:00
|
|
|
#include "vk_const.h"
|
|
|
|
#include "vk_common.h"
|
2021-02-14 02:19:59 +01:00
|
|
|
#include "vk_pipeline.h"
|
|
|
|
#include "vk_textures.h"
|
2021-02-20 21:00:31 +01:00
|
|
|
#include "vk_math.h"
|
2021-02-27 22:43:49 +01:00
|
|
|
#include "vk_rtx.h"
|
2021-03-07 01:40:35 +01:00
|
|
|
#include "vk_descriptor.h"
|
2022-05-14 22:36:33 +02:00
|
|
|
#include "vk_framectl.h" // FIXME needed for dynamic models cmdbuf
|
|
|
|
#include "alolcator.h"
|
2021-02-10 19:33:44 +01:00
|
|
|
|
|
|
|
#include "eiface.h"
|
|
|
|
#include "xash3d_mathlib.h"
|
2021-03-07 01:40:35 +01:00
|
|
|
#include "protocol.h" // MAX_DLIGHTS
|
2021-02-10 19:33:44 +01:00
|
|
|
|
2021-02-20 21:00:31 +01:00
|
|
|
#include <memory.h>
|
|
|
|
|
|
|
|
#define MAX_UNIFORM_SLOTS (MAX_SCENE_ENTITIES * 2 /* solid + trans */ + 1)
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
#define MAX_BUFFER_VERTICES_STATIC (128 * 1024)
|
|
|
|
#define MAX_BUFFER_INDICES_STATIC (MAX_BUFFER_VERTICES_STATIC * 3)
|
|
|
|
#define GEOMETRY_BUFFER_STATIC_SIZE ALIGN_UP(MAX_BUFFER_VERTICES_STATIC * sizeof(vk_vertex_t) + MAX_BUFFER_INDICES_STATIC * sizeof(uint16_t), sizeof(vk_vertex_t))
|
|
|
|
|
|
|
|
#define MAX_BUFFER_VERTICES_DYNAMIC (128 * 1024)
|
|
|
|
#define MAX_BUFFER_INDICES_DYNAMIC (MAX_BUFFER_VERTICES_DYNAMIC * 3)
|
|
|
|
#define GEOMETRY_BUFFER_DYNAMIC_SIZE ALIGN_UP(MAX_BUFFER_VERTICES_DYNAMIC * sizeof(vk_vertex_t) + MAX_BUFFER_INDICES_DYNAMIC * sizeof(uint16_t), sizeof(vk_vertex_t))
|
|
|
|
|
|
|
|
#define GEOMETRY_BUFFER_SIZE (GEOMETRY_BUFFER_STATIC_SIZE + GEOMETRY_BUFFER_DYNAMIC_SIZE)
|
|
|
|
|
2021-02-20 21:00:31 +01:00
|
|
|
typedef struct {
|
|
|
|
matrix4x4 mvp;
|
|
|
|
vec4_t color;
|
|
|
|
} uniform_data_t;
|
|
|
|
|
2021-02-10 19:33:44 +01:00
|
|
|
static struct {
|
2021-02-20 21:00:31 +01:00
|
|
|
VkPipelineLayout pipeline_layout;
|
|
|
|
VkPipeline pipelines[kRenderTransAdd + 1];
|
|
|
|
|
2021-02-10 19:33:44 +01:00
|
|
|
vk_buffer_t uniform_buffer;
|
2021-03-03 20:58:40 +01:00
|
|
|
uint32_t ubo_align;
|
2021-02-10 19:33:44 +01:00
|
|
|
|
2021-08-05 03:36:53 +02:00
|
|
|
float fov_angle_y;
|
2021-02-14 02:19:59 +01:00
|
|
|
} g_render;
|
2021-02-10 19:33:44 +01:00
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
struct {
|
|
|
|
vk_buffer_t buffer;
|
|
|
|
alo_ring_t static_ring;
|
|
|
|
alo_ring_t dynamic_ring;
|
|
|
|
|
|
|
|
int frame_index;
|
|
|
|
uint32_t dynamic_offsets[MAX_CONCURRENT_FRAMES];
|
|
|
|
} g_geom;
|
|
|
|
|
2021-02-14 02:19:59 +01:00
|
|
|
static qboolean createPipelines( void )
|
|
|
|
{
|
|
|
|
/* VkPushConstantRange push_const = { */
|
|
|
|
/* .offset = 0, */
|
|
|
|
/* .size = sizeof(AVec3f), */
|
|
|
|
/* .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, */
|
|
|
|
/* }; */
|
|
|
|
|
|
|
|
VkDescriptorSetLayout descriptor_layouts[] = {
|
2021-03-07 01:40:35 +01:00
|
|
|
vk_desc.one_uniform_buffer_layout,
|
|
|
|
vk_desc.one_texture_layout,
|
|
|
|
vk_desc.one_texture_layout,
|
|
|
|
vk_desc.one_uniform_buffer_layout,
|
2021-02-14 02:19:59 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
VkPipelineLayoutCreateInfo plci = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
|
|
.setLayoutCount = ARRAYSIZE(descriptor_layouts),
|
|
|
|
.pSetLayouts = descriptor_layouts,
|
|
|
|
/* .pushConstantRangeCount = 1, */
|
|
|
|
/* .pPushConstantRanges = &push_const, */
|
|
|
|
};
|
|
|
|
|
|
|
|
// FIXME store layout separately
|
|
|
|
XVK_CHECK(vkCreatePipelineLayout(vk_core.device, &plci, NULL, &g_render.pipeline_layout));
|
|
|
|
|
|
|
|
{
|
|
|
|
struct ShaderSpec {
|
|
|
|
float alpha_test_threshold;
|
2021-03-07 01:40:35 +01:00
|
|
|
uint32_t max_dlights;
|
|
|
|
} spec_data = { .25f, MAX_DLIGHTS };
|
2021-02-14 02:19:59 +01:00
|
|
|
const VkSpecializationMapEntry spec_map[] = {
|
|
|
|
{.constantID = 0, .offset = offsetof(struct ShaderSpec, alpha_test_threshold), .size = sizeof(float) },
|
2021-03-07 01:40:35 +01:00
|
|
|
{.constantID = 1, .offset = offsetof(struct ShaderSpec, max_dlights), .size = sizeof(uint32_t) },
|
2021-02-14 02:19:59 +01:00
|
|
|
};
|
|
|
|
|
2021-03-07 01:40:35 +01:00
|
|
|
VkSpecializationInfo shader_spec = {
|
2021-02-14 02:19:59 +01:00
|
|
|
.mapEntryCount = ARRAYSIZE(spec_map),
|
|
|
|
.pMapEntries = spec_map,
|
|
|
|
.dataSize = sizeof(struct ShaderSpec),
|
|
|
|
.pData = &spec_data
|
|
|
|
};
|
|
|
|
|
2021-03-13 21:29:17 +01:00
|
|
|
const VkVertexInputAttributeDescription attribs[] = {
|
2021-02-17 22:26:09 +01:00
|
|
|
{.binding = 0, .location = 0, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vk_vertex_t, pos)},
|
2021-03-07 01:40:35 +01:00
|
|
|
{.binding = 0, .location = 1, .format = VK_FORMAT_R32G32B32_SFLOAT, .offset = offsetof(vk_vertex_t, normal)},
|
|
|
|
{.binding = 0, .location = 2, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(vk_vertex_t, gl_tc)},
|
|
|
|
{.binding = 0, .location = 3, .format = VK_FORMAT_R32G32_SFLOAT, .offset = offsetof(vk_vertex_t, lm_tc)},
|
2021-08-08 04:56:38 +02:00
|
|
|
{.binding = 0, .location = 4, .format = VK_FORMAT_R8G8B8A8_UNORM, .offset = offsetof(vk_vertex_t, color)},
|
|
|
|
{.binding = 0, .location = 5, .format = VK_FORMAT_R32_UINT, .offset = offsetof(vk_vertex_t, flags)},
|
2021-02-14 02:19:59 +01:00
|
|
|
};
|
|
|
|
|
2021-03-13 21:29:17 +01:00
|
|
|
const vk_shader_stage_t shader_stages[] = {
|
2021-02-14 02:19:59 +01:00
|
|
|
{
|
|
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
2021-03-13 21:29:17 +01:00
|
|
|
.filename = "brush.vert.spv",
|
|
|
|
.specialization_info = NULL,
|
2021-02-14 02:19:59 +01:00
|
|
|
}, {
|
|
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
2021-03-13 21:29:17 +01:00
|
|
|
.filename = "brush.frag.spv",
|
|
|
|
.specialization_info = &shader_spec,
|
2021-02-14 02:19:59 +01:00
|
|
|
}};
|
|
|
|
|
2021-03-13 21:29:17 +01:00
|
|
|
vk_pipeline_graphics_create_info_t ci = {
|
2021-02-14 02:19:59 +01:00
|
|
|
.layout = g_render.pipeline_layout,
|
|
|
|
.attribs = attribs,
|
|
|
|
.num_attribs = ARRAYSIZE(attribs),
|
|
|
|
|
|
|
|
.stages = shader_stages,
|
|
|
|
.num_stages = ARRAYSIZE(shader_stages),
|
|
|
|
|
2021-02-17 22:26:09 +01:00
|
|
|
.vertex_stride = sizeof(vk_vertex_t),
|
2021-02-14 02:19:59 +01:00
|
|
|
|
|
|
|
.depthTestEnable = VK_TRUE,
|
|
|
|
.depthWriteEnable = VK_TRUE,
|
|
|
|
.depthCompareOp = VK_COMPARE_OP_LESS,
|
|
|
|
|
|
|
|
.blendEnable = VK_FALSE,
|
|
|
|
|
|
|
|
.cullMode = VK_CULL_MODE_FRONT_BIT,
|
|
|
|
};
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAYSIZE(g_render.pipelines); ++i)
|
|
|
|
{
|
|
|
|
const char *name = "UNDEFINED";
|
|
|
|
switch (i)
|
|
|
|
{
|
|
|
|
case kRenderNormal:
|
2021-03-07 01:40:35 +01:00
|
|
|
spec_data.alpha_test_threshold = 0.f;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.blendEnable = VK_FALSE;
|
|
|
|
ci.depthWriteEnable = VK_TRUE;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.depthTestEnable = VK_TRUE;
|
2021-02-14 02:19:59 +01:00
|
|
|
name = "brush kRenderNormal";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kRenderTransColor:
|
2021-03-07 01:40:35 +01:00
|
|
|
spec_data.alpha_test_threshold = 0.f;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.depthWriteEnable = VK_TRUE;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.depthTestEnable = VK_TRUE;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.blendEnable = VK_TRUE;
|
|
|
|
ci.colorBlendOp = VK_BLEND_OP_ADD; // TODO check
|
|
|
|
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
|
|
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
|
|
name = "brush kRenderTransColor";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kRenderTransAdd:
|
2021-03-07 01:40:35 +01:00
|
|
|
spec_data.alpha_test_threshold = 0.f;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.depthWriteEnable = VK_FALSE;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.depthTestEnable = VK_TRUE;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.blendEnable = VK_TRUE;
|
|
|
|
ci.colorBlendOp = VK_BLEND_OP_ADD; // TODO check
|
2021-02-20 21:00:31 +01:00
|
|
|
|
|
|
|
// sprites do SRC_ALPHA
|
|
|
|
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;// TODO ? FACTOR_ONE;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
|
|
name = "brush kRenderTransAdd";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kRenderTransAlpha:
|
2021-03-07 01:40:35 +01:00
|
|
|
spec_data.alpha_test_threshold = .25f;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.depthWriteEnable = VK_TRUE;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.depthTestEnable = VK_TRUE;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.blendEnable = VK_FALSE;
|
|
|
|
name = "brush kRenderTransAlpha(test)";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case kRenderGlow:
|
2021-03-07 01:40:35 +01:00
|
|
|
spec_data.alpha_test_threshold = 0.f;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.depthWriteEnable = VK_FALSE;
|
2021-08-22 19:44:47 +02:00
|
|
|
ci.depthTestEnable = VK_TRUE;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.blendEnable = VK_TRUE;
|
|
|
|
ci.colorBlendOp = VK_BLEND_OP_ADD; // TODO check
|
|
|
|
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
|
|
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
|
|
break;
|
|
|
|
|
2021-02-14 02:19:59 +01:00
|
|
|
case kRenderTransTexture:
|
2021-03-07 01:40:35 +01:00
|
|
|
spec_data.alpha_test_threshold = 0.f;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.depthWriteEnable = VK_FALSE;
|
2021-02-20 21:46:16 +01:00
|
|
|
ci.depthTestEnable = VK_TRUE;
|
2021-02-14 02:19:59 +01:00
|
|
|
ci.blendEnable = VK_TRUE;
|
|
|
|
ci.colorBlendOp = VK_BLEND_OP_ADD; // TODO check
|
|
|
|
ci.srcAlphaBlendFactor = ci.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
|
|
ci.dstAlphaBlendFactor = ci.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
|
|
|
name = "brush kRenderTransTexture/Glow";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
ASSERT(!"Unreachable");
|
|
|
|
}
|
|
|
|
|
2021-03-13 21:29:17 +01:00
|
|
|
g_render.pipelines[i] = VK_PipelineGraphicsCreate(&ci);
|
2021-02-14 02:19:59 +01:00
|
|
|
|
|
|
|
if (!g_render.pipelines[i])
|
|
|
|
{
|
|
|
|
// TODO complain
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vk_core.debug)
|
|
|
|
{
|
|
|
|
VkDebugUtilsObjectNameInfoEXT debug_name = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT,
|
|
|
|
.objectHandle = (uint64_t)g_render.pipelines[i],
|
|
|
|
.objectType = VK_OBJECT_TYPE_PIPELINE,
|
|
|
|
.pObjectName = name,
|
|
|
|
};
|
|
|
|
XVK_CHECK(vkSetDebugUtilsObjectNameEXT(vk_core.device, &debug_name));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-03-07 01:40:35 +01:00
|
|
|
typedef struct {
|
|
|
|
uint32_t num_lights, pad[3];
|
|
|
|
struct {
|
|
|
|
vec4_t pos_r;
|
|
|
|
vec4_t color;
|
|
|
|
} light[MAX_DLIGHTS];
|
|
|
|
} vk_ubo_lights_t;
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
qboolean VK_RenderInit( void ) {
|
2021-03-03 20:58:40 +01:00
|
|
|
uint32_t uniform_unit_size;
|
2021-02-10 19:33:44 +01:00
|
|
|
|
2021-03-03 20:58:40 +01:00
|
|
|
g_render.ubo_align = Q_max(4, vk_core.physical_device.properties.limits.minUniformBufferOffsetAlignment);
|
|
|
|
uniform_unit_size = ((sizeof(uniform_data_t) + g_render.ubo_align - 1) / g_render.ubo_align) * g_render.ubo_align;
|
2021-02-10 19:33:44 +01:00
|
|
|
|
|
|
|
// TODO device memory and friends (e.g. handle mobile memory ...)
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
if (!VK_BufferCreate("geometry buffer", &g_geom.buffer, GEOMETRY_BUFFER_SIZE,
|
2022-05-04 18:23:37 +02:00
|
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | (vk_core.rtx ? VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0),
|
|
|
|
(vk_core.rtx ? VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0))) // TODO staging buffer?
|
2021-02-10 19:33:44 +01:00
|
|
|
return false;
|
|
|
|
|
2022-01-09 20:14:44 +01:00
|
|
|
if (!VK_BufferCreate("render uniform_buffer", &g_render.uniform_buffer, uniform_unit_size * MAX_UNIFORM_SLOTS,
|
2021-03-15 18:23:26 +01:00
|
|
|
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
|
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | (vk_core.rtx ? VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT : 0))) // TODO staging buffer?
|
2021-02-10 19:33:44 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
{
|
2021-03-07 01:40:35 +01:00
|
|
|
VkDescriptorBufferInfo dbi_uniform_data = {
|
2021-02-10 19:33:44 +01:00
|
|
|
.buffer = g_render.uniform_buffer.buffer,
|
|
|
|
.offset = 0,
|
|
|
|
.range = sizeof(uniform_data_t),
|
|
|
|
};
|
2021-03-07 01:40:35 +01:00
|
|
|
VkDescriptorBufferInfo dbi_uniform_lights = {
|
|
|
|
.buffer = g_render.uniform_buffer.buffer,
|
|
|
|
.offset = 0,
|
|
|
|
.range = sizeof(vk_ubo_lights_t),
|
|
|
|
};
|
|
|
|
VkWriteDescriptorSet wds[] = {{
|
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstBinding = 0,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
|
|
|
.pBufferInfo = &dbi_uniform_data,
|
|
|
|
.dstSet = vk_desc.ubo_sets[0], // FIXME
|
|
|
|
}, {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
|
|
.dstBinding = 0,
|
|
|
|
.dstArrayElement = 0,
|
|
|
|
.descriptorCount = 1,
|
|
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
|
|
|
|
.pBufferInfo = &dbi_uniform_lights,
|
|
|
|
.dstSet = vk_desc.ubo_sets[1], // FIXME
|
|
|
|
}};
|
2021-02-10 19:33:44 +01:00
|
|
|
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
|
|
|
}
|
|
|
|
|
2021-02-14 02:19:59 +01:00
|
|
|
if (!createPipelines())
|
|
|
|
return false;
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
XVK_RenderBufferMapClear();
|
2021-05-03 20:17:01 +02:00
|
|
|
|
2021-02-10 19:33:44 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VK_RenderShutdown( void )
|
|
|
|
{
|
2021-02-14 02:19:59 +01:00
|
|
|
for (int i = 0; i < ARRAYSIZE(g_render.pipelines); ++i)
|
|
|
|
vkDestroyPipeline(vk_core.device, g_render.pipelines[i], NULL);
|
|
|
|
vkDestroyPipelineLayout( vk_core.device, g_render.pipeline_layout, NULL );
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
VK_BufferDestroy( &g_geom.buffer );
|
2022-01-09 20:14:44 +01:00
|
|
|
VK_BufferDestroy( &g_render.uniform_buffer );
|
2021-02-10 19:33:44 +01:00
|
|
|
}
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
qboolean R_GeometryBufferAllocAndLock( r_geometry_buffer_lock_t *lock, int vertex_count, int index_count, r_geometry_lifetime_t lifetime ) {
|
2022-05-04 18:23:37 +02:00
|
|
|
const uint32_t vertices_size = vertex_count * sizeof(vk_vertex_t);
|
|
|
|
const uint32_t indices_size = index_count * sizeof(uint16_t);
|
|
|
|
const uint32_t total_size = vertices_size + indices_size;
|
2022-05-14 22:36:33 +02:00
|
|
|
alo_ring_t * const ring = (lifetime != LifetimeSingleFrame) ? &g_geom.static_ring : &g_geom.dynamic_ring;
|
|
|
|
|
|
|
|
const uint32_t alloc_offset = aloRingAlloc(ring, total_size, sizeof(vk_vertex_t));
|
|
|
|
const uint32_t offset = alloc_offset + ((lifetime == LifetimeSingleFrame) ? GEOMETRY_BUFFER_STATIC_SIZE : 0);
|
|
|
|
if (alloc_offset == ALO_ALLOC_FAILED) {
|
|
|
|
gEngine.Con_Printf(S_ERROR "Cannot allocate %s geometry buffer for %d vertices (%d bytes) and %d indices (%d bytes)\n",
|
|
|
|
lifetime == LifetimeSingleFrame ? "dynamic" : "static",
|
|
|
|
vertex_count, vertices_size, index_count, indices_size);
|
2022-05-04 18:23:37 +02:00
|
|
|
return false;
|
2021-02-10 19:33:44 +01:00
|
|
|
}
|
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
// Store first dynamic allocation this frame
|
|
|
|
if (lifetime == LifetimeSingleFrame && g_geom.dynamic_offsets[g_geom.frame_index] == ALO_ALLOC_FAILED) {
|
2022-06-04 19:49:34 +02:00
|
|
|
//gEngine.Con_Reportf("FRAME=%d FIRST_OFFSET=%d\n", g_geom.frame_index, alloc_offset);
|
2022-05-14 22:36:33 +02:00
|
|
|
g_geom.dynamic_offsets[g_geom.frame_index] = alloc_offset;
|
|
|
|
}
|
|
|
|
|
2022-05-04 18:23:37 +02:00
|
|
|
{
|
|
|
|
const uint32_t vertices_offset = offset / sizeof(vk_vertex_t);
|
|
|
|
const uint32_t indices_offset = (offset + vertices_size) / sizeof(uint16_t);
|
2022-06-04 23:04:44 +02:00
|
|
|
const vk_staging_buffer_args_t staging_args = {
|
|
|
|
.buffer = g_geom.buffer.buffer,
|
|
|
|
.offset = offset,
|
|
|
|
.size = total_size,
|
|
|
|
.alignment = 4,
|
|
|
|
};
|
2021-02-23 03:54:13 +01:00
|
|
|
|
2022-06-04 23:04:44 +02:00
|
|
|
const vk_staging_region_t staging = R_VkStagingLockForBuffer(staging_args);
|
2022-05-04 18:23:37 +02:00
|
|
|
ASSERT(staging.ptr);
|
|
|
|
|
|
|
|
ASSERT( offset % sizeof(vk_vertex_t) == 0 );
|
|
|
|
ASSERT( (offset + vertices_size) % sizeof(uint16_t) == 0 );
|
|
|
|
|
|
|
|
*lock = (r_geometry_buffer_lock_t) {
|
|
|
|
.vertices = {
|
|
|
|
.count = vertex_count,
|
|
|
|
.ptr = (vk_vertex_t *)staging.ptr,
|
|
|
|
.unit_offset = vertices_offset,
|
|
|
|
},
|
|
|
|
.indices = {
|
|
|
|
.count = index_count,
|
|
|
|
.ptr = (uint16_t *)((char*)staging.ptr + vertices_size),
|
|
|
|
.unit_offset = indices_offset,
|
|
|
|
},
|
|
|
|
.impl_ = {
|
|
|
|
.staging_handle = staging.handle,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2021-02-10 19:33:44 +01:00
|
|
|
}
|
2021-02-14 02:19:59 +01:00
|
|
|
|
2022-05-04 18:23:37 +02:00
|
|
|
void R_GeometryBufferUnlock( const r_geometry_buffer_lock_t *lock ) {
|
2022-06-04 23:04:44 +02:00
|
|
|
R_VkStagingUnlock(lock->impl_.staging_handle);
|
2021-02-14 02:19:59 +01:00
|
|
|
}
|
|
|
|
|
2021-08-11 20:43:33 +02:00
|
|
|
void XVK_RenderBufferMapClear( void ) {
|
2022-05-14 22:36:33 +02:00
|
|
|
aloRingInit(&g_geom.static_ring, GEOMETRY_BUFFER_STATIC_SIZE);
|
|
|
|
aloRingInit(&g_geom.dynamic_ring, GEOMETRY_BUFFER_DYNAMIC_SIZE);
|
|
|
|
for (int i = 0; i < COUNTOF(g_geom.dynamic_offsets); ++i) {
|
|
|
|
g_geom.dynamic_offsets[i] = ALO_ALLOC_FAILED;
|
|
|
|
}
|
|
|
|
g_geom.frame_index = 0;
|
2021-05-03 20:17:01 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 20:43:33 +02:00
|
|
|
void XVK_RenderBufferPrintStats( void ) {
|
|
|
|
// TODO get alignment holes size
|
2021-05-03 20:17:01 +02:00
|
|
|
gEngine.Con_Reportf("Buffer usage: %uKiB of (%uKiB)\n",
|
2022-05-14 22:36:33 +02:00
|
|
|
g_geom.static_ring.head / 1024, g_geom.static_ring.size / 1024);
|
2021-02-14 02:19:59 +01:00
|
|
|
}
|
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
#define MAX_DRAW_COMMANDS 8192 // TODO estimate
|
|
|
|
#define MAX_DEBUG_NAME_LENGTH 32
|
|
|
|
|
2021-04-24 21:53:42 +02:00
|
|
|
typedef struct render_draw_s {
|
|
|
|
int lightmap, texture;
|
|
|
|
int render_mode;
|
|
|
|
uint32_t element_count;
|
|
|
|
uint32_t index_offset, vertex_offset;
|
|
|
|
/* TODO this should be a separate thing? */ struct { float r, g, b; } emissive;
|
|
|
|
} render_draw_t;
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
enum draw_command_type_e {
|
|
|
|
DrawLabelBegin,
|
|
|
|
DrawLabelEnd,
|
|
|
|
DrawDraw
|
|
|
|
};
|
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
typedef struct {
|
2021-08-15 20:02:57 +02:00
|
|
|
enum draw_command_type_e type;
|
|
|
|
union {
|
|
|
|
char debug_label[MAX_DEBUG_NAME_LENGTH];
|
|
|
|
struct {
|
|
|
|
render_draw_t draw;
|
|
|
|
uint32_t ubo_offset;
|
|
|
|
matrix3x4 transform;
|
|
|
|
} draw;
|
|
|
|
};
|
2021-02-20 23:54:57 +01:00
|
|
|
} draw_command_t;
|
2021-02-20 21:00:31 +01:00
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
static struct {
|
2021-02-20 21:00:31 +01:00
|
|
|
int uniform_data_set_mask;
|
|
|
|
uniform_data_t current_uniform_data;
|
|
|
|
uniform_data_t dirty_uniform_data;
|
2021-02-20 23:54:57 +01:00
|
|
|
|
2021-03-03 20:58:40 +01:00
|
|
|
uint32_t current_ubo_offset;
|
|
|
|
uint32_t uniform_free_offset;
|
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
draw_command_t draw_commands[MAX_DRAW_COMMANDS];
|
|
|
|
int num_draw_commands;
|
2021-03-03 20:58:40 +01:00
|
|
|
|
2021-03-13 22:35:50 +01:00
|
|
|
matrix4x4 model, view, projection;
|
2021-07-04 20:18:28 +02:00
|
|
|
|
|
|
|
qboolean current_frame_is_ray_traced;
|
2021-02-14 02:19:59 +01:00
|
|
|
} g_render_state;
|
|
|
|
|
2021-02-20 21:00:31 +01:00
|
|
|
enum {
|
|
|
|
UNIFORM_UNSET = 0,
|
|
|
|
UNIFORM_SET_COLOR = 1,
|
2021-03-13 22:35:50 +01:00
|
|
|
UNIFORM_SET_MATRIX_MODEL = 2,
|
|
|
|
UNIFORM_SET_MATRIX_VIEW = 4,
|
|
|
|
UNIFORM_SET_MATRIX_PROJECTION = 8,
|
|
|
|
UNIFORM_SET_ALL = UNIFORM_SET_COLOR | UNIFORM_SET_MATRIX_MODEL | UNIFORM_SET_MATRIX_VIEW | UNIFORM_SET_MATRIX_PROJECTION,
|
|
|
|
UNIFORM_UPLOADED = 16,
|
2021-02-20 21:00:31 +01:00
|
|
|
};
|
|
|
|
|
2021-07-04 20:18:28 +02:00
|
|
|
void VK_RenderBegin( qboolean ray_tracing ) {
|
2022-05-14 22:36:33 +02:00
|
|
|
g_render_state.uniform_free_offset = 0; // FIXME multiple frames in flight
|
2021-02-20 21:00:31 +01:00
|
|
|
g_render_state.uniform_data_set_mask = UNIFORM_UNSET;
|
2021-03-03 20:58:40 +01:00
|
|
|
g_render_state.current_ubo_offset = UINT32_MAX;
|
2021-02-20 21:00:31 +01:00
|
|
|
|
|
|
|
memset(&g_render_state.current_uniform_data, 0, sizeof(g_render_state.current_uniform_data));
|
|
|
|
memset(&g_render_state.dirty_uniform_data, 0, sizeof(g_render_state.dirty_uniform_data));
|
2021-02-14 02:19:59 +01:00
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
g_render_state.num_draw_commands = 0;
|
2021-07-04 20:18:28 +02:00
|
|
|
g_render_state.current_frame_is_ray_traced = ray_tracing;
|
2021-04-09 23:59:04 +02:00
|
|
|
|
2022-05-14 22:36:33 +02:00
|
|
|
{
|
|
|
|
const int new_frame = (g_geom.frame_index + 1) % COUNTOF(g_geom.dynamic_offsets);
|
|
|
|
if (g_geom.dynamic_offsets[new_frame] != ALO_ALLOC_FAILED) {
|
2022-06-04 19:49:34 +02:00
|
|
|
//gEngine.Con_Reportf("FRAME=%d FREE_OFFSET=%d\n", g_geom.frame_index, g_geom.dynamic_offsets[new_frame]);
|
2022-05-14 22:36:33 +02:00
|
|
|
aloRingFree(&g_geom.dynamic_ring, g_geom.dynamic_offsets[new_frame]);
|
|
|
|
g_geom.dynamic_offsets[new_frame] = ALO_ALLOC_FAILED;
|
|
|
|
}
|
|
|
|
g_geom.frame_index = new_frame;
|
|
|
|
}
|
|
|
|
|
2021-07-04 20:18:28 +02:00
|
|
|
if (ray_tracing)
|
2021-04-09 23:59:04 +02:00
|
|
|
VK_RayFrameBegin();
|
2021-02-14 02:19:59 +01:00
|
|
|
}
|
|
|
|
|
2021-02-20 21:00:31 +01:00
|
|
|
void VK_RenderStateSetColor( float r, float g, float b, float a )
|
|
|
|
{
|
|
|
|
g_render_state.uniform_data_set_mask |= UNIFORM_SET_COLOR;
|
|
|
|
g_render_state.dirty_uniform_data.color[0] = r;
|
|
|
|
g_render_state.dirty_uniform_data.color[1] = g;
|
|
|
|
g_render_state.dirty_uniform_data.color[2] = b;
|
|
|
|
g_render_state.dirty_uniform_data.color[3] = a;
|
|
|
|
}
|
|
|
|
|
2021-03-21 00:21:26 +01:00
|
|
|
// Vulkan has Y pointing down, and z should end up in (0, 1)
|
|
|
|
// NOTE this matrix is row-major
|
|
|
|
static const matrix4x4 vk_proj_fixup = {
|
|
|
|
{1, 0, 0, 0},
|
|
|
|
{0, -1, 0, 0},
|
|
|
|
{0, 0, .5, .5},
|
|
|
|
{0, 0, 0, 1}
|
|
|
|
};
|
|
|
|
|
2021-08-05 03:36:53 +02:00
|
|
|
void VK_RenderStateSetMatrixProjection(const matrix4x4 projection, float fov_angle_y)
|
2021-02-20 21:00:31 +01:00
|
|
|
{
|
2021-03-13 22:35:50 +01:00
|
|
|
g_render_state.uniform_data_set_mask |= UNIFORM_SET_MATRIX_PROJECTION;
|
|
|
|
Matrix4x4_Concat( g_render_state.projection, vk_proj_fixup, projection );
|
2021-08-05 03:36:53 +02:00
|
|
|
g_render.fov_angle_y = fov_angle_y;
|
2021-02-20 21:00:31 +01:00
|
|
|
}
|
|
|
|
|
2021-03-13 22:35:50 +01:00
|
|
|
void VK_RenderStateSetMatrixView(const matrix4x4 view)
|
2021-02-20 21:00:31 +01:00
|
|
|
{
|
2021-03-13 22:35:50 +01:00
|
|
|
g_render_state.uniform_data_set_mask |= UNIFORM_SET_MATRIX_VIEW;
|
|
|
|
Matrix4x4_Copy(g_render_state.view, view);
|
2021-02-20 21:00:31 +01:00
|
|
|
}
|
|
|
|
|
2021-03-13 22:35:50 +01:00
|
|
|
void VK_RenderStateSetMatrixModel( const matrix4x4 model )
|
2021-03-03 20:58:40 +01:00
|
|
|
{
|
2021-03-13 22:35:50 +01:00
|
|
|
g_render_state.uniform_data_set_mask |= UNIFORM_SET_MATRIX_MODEL;
|
|
|
|
Matrix4x4_Copy(g_render_state.model, model);
|
|
|
|
|
|
|
|
// Assume that projection and view matrices are already properly set
|
|
|
|
ASSERT(g_render_state.uniform_data_set_mask & UNIFORM_SET_MATRIX_VIEW);
|
|
|
|
ASSERT(g_render_state.uniform_data_set_mask & UNIFORM_SET_MATRIX_PROJECTION);
|
|
|
|
|
|
|
|
{
|
|
|
|
matrix4x4 mv, mvp;
|
|
|
|
// TODO this can be cached (on a really slow device?)
|
|
|
|
Matrix4x4_Concat(mv, g_render_state.view, g_render_state.model);
|
|
|
|
Matrix4x4_Concat(mvp, g_render_state.projection, mv);
|
|
|
|
Matrix4x4_ToArrayFloatGL(mvp, (float*)g_render_state.dirty_uniform_data.mvp);
|
|
|
|
}
|
2021-03-03 20:58:40 +01:00
|
|
|
}
|
2021-02-20 21:00:31 +01:00
|
|
|
|
2021-03-03 20:58:40 +01:00
|
|
|
static uint32_t allocUniform( uint32_t size, uint32_t alignment ) {
|
|
|
|
// FIXME Q_max is not correct, we need NAIMENSCHEEE OBSCHEEE KRATNOE
|
|
|
|
const uint32_t align = Q_max(alignment, g_render.ubo_align);
|
|
|
|
const uint32_t offset = (((g_render_state.uniform_free_offset + align - 1) / align) * align);
|
|
|
|
if (offset + size > g_render.uniform_buffer.size)
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
|
|
|
g_render_state.uniform_free_offset = offset + size;
|
|
|
|
return offset;
|
2021-02-20 21:00:31 +01:00
|
|
|
}
|
|
|
|
|
2021-08-15 20:14:33 +02:00
|
|
|
static draw_command_t *drawCmdAlloc( void ) {
|
2021-08-15 20:02:57 +02:00
|
|
|
ASSERT(g_render_state.num_draw_commands < ARRAYSIZE(g_render_state.draw_commands));
|
|
|
|
return g_render_state.draw_commands + (g_render_state.num_draw_commands++);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawCmdPushDebugLabelBegin( const char *debug_label ) {
|
|
|
|
if (vk_core.debug) {
|
|
|
|
draw_command_t *draw_command = drawCmdAlloc();
|
|
|
|
draw_command->type = DrawLabelBegin;
|
|
|
|
Q_strncpy(draw_command->debug_label, debug_label, sizeof draw_command->debug_label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawCmdPushDebugLabelEnd( void ) {
|
|
|
|
if (vk_core.debug) {
|
|
|
|
draw_command_t *draw_command = drawCmdAlloc();
|
|
|
|
draw_command->type = DrawLabelEnd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void drawCmdPushDraw( const render_draw_t *draw )
|
2021-02-14 02:19:59 +01:00
|
|
|
{
|
2021-02-20 23:54:57 +01:00
|
|
|
draw_command_t *draw_command;
|
|
|
|
|
2021-02-14 02:19:59 +01:00
|
|
|
ASSERT(draw->render_mode >= 0);
|
|
|
|
ASSERT(draw->render_mode < ARRAYSIZE(g_render.pipelines));
|
|
|
|
ASSERT(draw->lightmap >= 0);
|
|
|
|
ASSERT(draw->texture >= 0);
|
2021-02-20 21:00:31 +01:00
|
|
|
|
|
|
|
if ((g_render_state.uniform_data_set_mask & UNIFORM_SET_ALL) != UNIFORM_SET_ALL) {
|
|
|
|
gEngine.Con_Printf( S_ERROR "Not all uniform state was initialized prior to rendering\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
if (g_render_state.num_draw_commands >= ARRAYSIZE(g_render_state.draw_commands)) {
|
|
|
|
gEngine.Con_Printf( S_ERROR "Maximum number of draw commands reached\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-02-20 21:00:31 +01:00
|
|
|
// Figure out whether we need to update UBO data, and upload new data if we do
|
2021-02-20 23:54:57 +01:00
|
|
|
// TODO generally it's not safe to do memcmp for structures comparison
|
2021-09-04 21:36:30 +02:00
|
|
|
if (g_render_state.current_ubo_offset == UINT32_MAX || ((g_render_state.uniform_data_set_mask & UNIFORM_UPLOADED) == 0)
|
|
|
|
|| memcmp(&g_render_state.current_uniform_data, &g_render_state.dirty_uniform_data, sizeof(g_render_state.current_uniform_data)) != 0) {
|
2021-02-20 21:00:31 +01:00
|
|
|
uniform_data_t *ubo;
|
2021-03-03 20:58:40 +01:00
|
|
|
g_render_state.current_ubo_offset = allocUniform( sizeof(uniform_data_t), 16 );
|
|
|
|
if (g_render_state.current_ubo_offset == UINT32_MAX) {
|
2021-02-20 21:00:31 +01:00
|
|
|
gEngine.Con_Printf( S_ERROR "Ran out of uniform slots\n" );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-03 20:58:40 +01:00
|
|
|
ubo = (uniform_data_t*)((byte*)g_render.uniform_buffer.mapped + g_render_state.current_ubo_offset);
|
2021-02-20 21:00:31 +01:00
|
|
|
memcpy(&g_render_state.current_uniform_data, &g_render_state.dirty_uniform_data, sizeof(g_render_state.dirty_uniform_data));
|
|
|
|
memcpy(ubo, &g_render_state.current_uniform_data, sizeof(*ubo));
|
|
|
|
g_render_state.uniform_data_set_mask |= UNIFORM_UPLOADED;
|
|
|
|
}
|
2021-02-14 02:19:59 +01:00
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
draw_command = drawCmdAlloc();
|
|
|
|
draw_command->draw.draw = *draw;
|
|
|
|
draw_command->draw.ubo_offset = g_render_state.current_ubo_offset;
|
|
|
|
draw_command->type = DrawDraw;
|
|
|
|
Matrix3x4_Copy(draw_command->draw.transform, g_render_state.model);
|
2021-02-20 23:54:57 +01:00
|
|
|
}
|
2021-02-14 02:19:59 +01:00
|
|
|
|
2021-03-10 18:38:06 +01:00
|
|
|
// Return offset of dlights data into UBO buffer
|
2021-03-21 00:21:26 +01:00
|
|
|
static uint32_t writeDlightsToUBO( void )
|
2021-03-10 18:38:06 +01:00
|
|
|
{
|
|
|
|
vk_ubo_lights_t* ubo_lights;
|
2021-03-14 01:33:17 +01:00
|
|
|
int num_lights = 0;
|
2021-03-10 18:38:06 +01:00
|
|
|
const uint32_t ubo_lights_offset = allocUniform(sizeof(*ubo_lights), 4);
|
|
|
|
if (ubo_lights_offset == UINT32_MAX) {
|
|
|
|
gEngine.Con_Printf(S_ERROR "Cannot allocate UBO for DLights\n");
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
ubo_lights = (vk_ubo_lights_t*)((byte*)(g_render.uniform_buffer.mapped) + ubo_lights_offset);
|
|
|
|
|
|
|
|
// TODO this should not be here (where? vk_scene?)
|
2021-03-14 01:33:17 +01:00
|
|
|
for (int i = 0; i < MAX_DLIGHTS && num_lights < ARRAYSIZE(ubo_lights->light); ++i) {
|
2021-03-10 18:38:06 +01:00
|
|
|
const dlight_t *l = gEngine.GetDynamicLight(i);
|
|
|
|
if( !l || l->die < gpGlobals->time || !l->radius )
|
|
|
|
continue;
|
|
|
|
Vector4Set(
|
2021-03-14 01:33:17 +01:00
|
|
|
ubo_lights->light[num_lights].color,
|
2021-03-10 18:38:06 +01:00
|
|
|
l->color.r / 255.f,
|
|
|
|
l->color.g / 255.f,
|
|
|
|
l->color.b / 255.f,
|
|
|
|
1.f);
|
|
|
|
Vector4Set(
|
2021-03-14 01:33:17 +01:00
|
|
|
ubo_lights->light[num_lights].pos_r,
|
2021-03-10 18:38:06 +01:00
|
|
|
l->origin[0],
|
|
|
|
l->origin[1],
|
|
|
|
l->origin[2],
|
|
|
|
l->radius);
|
2021-03-14 01:33:17 +01:00
|
|
|
|
|
|
|
num_lights++;
|
2021-03-10 18:38:06 +01:00
|
|
|
}
|
|
|
|
|
2021-03-14 01:33:17 +01:00
|
|
|
ubo_lights->num_lights = num_lights;
|
2021-03-10 18:38:06 +01:00
|
|
|
return ubo_lights_offset;
|
|
|
|
}
|
|
|
|
|
2022-06-25 20:12:48 +02:00
|
|
|
void VK_Render_FIXME_Barrier( VkCommandBuffer cmdbuf )
|
|
|
|
// FIXME
|
|
|
|
{
|
|
|
|
const VkBufferMemoryBarrier bmb[] = { {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
|
|
|
//.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, // FIXME
|
|
|
|
.dstAccessMask = VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT , // FIXME
|
|
|
|
.buffer = g_geom.buffer.buffer,
|
|
|
|
.offset = 0, // FIXME
|
|
|
|
.size = VK_WHOLE_SIZE, // FIXME
|
|
|
|
} };
|
|
|
|
vkCmdPipelineBarrier(cmdbuf,
|
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
|
|
|
//VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
|
|
|
//VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
|
|
|
|
VK_PIPELINE_STAGE_VERTEX_INPUT_BIT,
|
|
|
|
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
|
|
|
|
}
|
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
void VK_RenderEnd( VkCommandBuffer cmdbuf )
|
|
|
|
{
|
|
|
|
// TODO we can sort collected draw commands for more efficient and correct rendering
|
|
|
|
// that requires adding info about distance to camera for correct order-dependent blending
|
|
|
|
|
|
|
|
int pipeline = -1;
|
|
|
|
int texture = -1;
|
|
|
|
int lightmap = -1;
|
|
|
|
uint32_t ubo_offset = -1;
|
2021-02-14 02:19:59 +01:00
|
|
|
|
2021-03-10 18:38:06 +01:00
|
|
|
const uint32_t dlights_ubo_offset = writeDlightsToUBO();
|
|
|
|
if (dlights_ubo_offset == UINT32_MAX)
|
|
|
|
return;
|
|
|
|
|
2021-07-04 20:18:28 +02:00
|
|
|
ASSERT(!g_render_state.current_frame_is_ray_traced);
|
2021-02-27 22:43:49 +01:00
|
|
|
|
2021-02-14 02:19:59 +01:00
|
|
|
{
|
2021-02-20 23:54:57 +01:00
|
|
|
const VkDeviceSize offset = 0;
|
2022-05-14 22:36:33 +02:00
|
|
|
vkCmdBindVertexBuffers(cmdbuf, 0, 1, &g_geom.buffer.buffer, &offset);
|
|
|
|
vkCmdBindIndexBuffer(cmdbuf, g_geom.buffer.buffer, 0, VK_INDEX_TYPE_UINT16);
|
2021-02-14 02:19:59 +01:00
|
|
|
}
|
|
|
|
|
2022-02-11 07:46:23 +01:00
|
|
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 3, 1, vk_desc.ubo_sets + 1, 1, &dlights_ubo_offset);
|
2021-03-07 01:40:35 +01:00
|
|
|
|
2021-02-20 23:54:57 +01:00
|
|
|
for (int i = 0; i < g_render_state.num_draw_commands; ++i) {
|
|
|
|
const draw_command_t *const draw = g_render_state.draw_commands + i;
|
2021-02-14 02:19:59 +01:00
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
switch (draw->type) {
|
|
|
|
case DrawLabelBegin:
|
|
|
|
{
|
|
|
|
VkDebugUtilsLabelEXT label = {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT,
|
|
|
|
.pLabelName = draw->debug_label,
|
|
|
|
};
|
|
|
|
vkCmdBeginDebugUtilsLabelEXT(cmdbuf, &label);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
case DrawLabelEnd:
|
|
|
|
vkCmdEndDebugUtilsLabelEXT(cmdbuf);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ubo_offset != draw->draw.ubo_offset)
|
2021-02-20 23:54:57 +01:00
|
|
|
{
|
2021-08-15 20:02:57 +02:00
|
|
|
ubo_offset = draw->draw.ubo_offset;
|
2022-02-11 07:46:23 +01:00
|
|
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 0, 1, vk_desc.ubo_sets, 1, &ubo_offset);
|
2021-02-20 23:54:57 +01:00
|
|
|
}
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
if (pipeline != draw->draw.draw.render_mode) {
|
|
|
|
pipeline = draw->draw.draw.render_mode;
|
2022-02-11 07:46:23 +01:00
|
|
|
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipelines[pipeline]);
|
2021-02-20 23:54:57 +01:00
|
|
|
}
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
if (lightmap != draw->draw.draw.lightmap) {
|
|
|
|
lightmap = draw->draw.draw.lightmap;
|
2022-02-11 07:46:23 +01:00
|
|
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 2, 1, &findTexture(lightmap)->vk.descriptor, 0, NULL);
|
2021-02-20 23:54:57 +01:00
|
|
|
}
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
if (texture != draw->draw.draw.texture)
|
2021-02-20 23:54:57 +01:00
|
|
|
{
|
2021-08-15 20:02:57 +02:00
|
|
|
texture = draw->draw.draw.texture;
|
2021-02-20 23:54:57 +01:00
|
|
|
// TODO names/enums for binding points
|
2022-02-11 07:46:23 +01:00
|
|
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 1, 1, &findTexture(texture)->vk.descriptor, 0, NULL);
|
2021-02-20 23:54:57 +01:00
|
|
|
}
|
|
|
|
|
2021-08-11 20:43:33 +02:00
|
|
|
// Only indexed mode is supported
|
2021-08-15 20:02:57 +02:00
|
|
|
ASSERT(draw->draw.draw.index_offset >= 0);
|
2022-02-11 07:46:23 +01:00
|
|
|
vkCmdDrawIndexed(cmdbuf, draw->draw.draw.element_count, 1, draw->draw.draw.index_offset, draw->draw.draw.vertex_offset, 0);
|
2021-02-20 23:54:57 +01:00
|
|
|
}
|
2021-02-14 02:19:59 +01:00
|
|
|
}
|
2021-02-20 21:35:04 +01:00
|
|
|
|
|
|
|
void VK_RenderDebugLabelBegin( const char *name )
|
|
|
|
{
|
2021-08-15 20:02:57 +02:00
|
|
|
drawCmdPushDebugLabelBegin(name);
|
2021-02-20 21:35:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void VK_RenderDebugLabelEnd( void )
|
|
|
|
{
|
2021-08-15 20:02:57 +02:00
|
|
|
drawCmdPushDebugLabelEnd();
|
2021-02-20 21:35:04 +01:00
|
|
|
}
|
2021-02-27 22:43:49 +01:00
|
|
|
|
2021-03-01 20:22:58 +01:00
|
|
|
void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage img_dst, uint32_t w, uint32_t h )
|
2021-02-27 22:43:49 +01:00
|
|
|
{
|
|
|
|
ASSERT(vk_core.rtx);
|
2021-04-07 21:11:20 +02:00
|
|
|
|
2021-03-03 20:58:40 +01:00
|
|
|
{
|
2021-04-09 23:59:04 +02:00
|
|
|
const vk_ray_frame_render_args_t args = {
|
2021-03-03 20:58:40 +01:00
|
|
|
.cmdbuf = cmdbuf,
|
|
|
|
.dst = {
|
|
|
|
.image_view = img_dst_view,
|
|
|
|
.image = img_dst,
|
|
|
|
.width = w,
|
|
|
|
.height = h,
|
|
|
|
},
|
2022-01-08 22:44:02 +01:00
|
|
|
|
|
|
|
.projection = &g_render_state.projection,
|
|
|
|
.view = &g_render_state.view,
|
2021-03-08 21:09:11 +01:00
|
|
|
|
|
|
|
.geometry_data = {
|
2022-05-14 22:36:33 +02:00
|
|
|
.buffer = g_geom.buffer.buffer,
|
2021-05-03 20:17:01 +02:00
|
|
|
.size = VK_WHOLE_SIZE,
|
2021-03-08 21:09:11 +01:00
|
|
|
},
|
2021-08-05 03:36:53 +02:00
|
|
|
|
|
|
|
.fov_angle_y = g_render.fov_angle_y,
|
2021-03-03 20:58:40 +01:00
|
|
|
};
|
|
|
|
|
2021-04-09 23:59:04 +02:00
|
|
|
VK_RayFrameEnd(&args);
|
2021-03-03 20:58:40 +01:00
|
|
|
}
|
2021-02-27 22:43:49 +01:00
|
|
|
}
|
2021-04-07 21:11:20 +02:00
|
|
|
|
2022-02-21 01:00:33 +01:00
|
|
|
qboolean VK_RenderModelInit( VkCommandBuffer cmdbuf, vk_render_model_t *model ) {
|
2021-07-04 20:18:28 +02:00
|
|
|
if (vk_core.rtx && (g_render_state.current_frame_is_ray_traced || !model->dynamic)) {
|
2021-04-09 23:59:04 +02:00
|
|
|
// TODO runtime rtx switch: ???
|
|
|
|
const vk_ray_model_init_t args = {
|
2022-05-14 22:36:33 +02:00
|
|
|
.buffer = g_geom.buffer.buffer,
|
2021-04-09 23:59:04 +02:00
|
|
|
.model = model,
|
|
|
|
};
|
2022-05-04 18:23:37 +02:00
|
|
|
R_VkStagingCommit(cmdbuf);
|
|
|
|
{
|
|
|
|
const VkBufferMemoryBarrier bmb[] = { {
|
|
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
|
|
|
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
2022-05-14 22:36:33 +02:00
|
|
|
//.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR, // FIXME
|
|
|
|
.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR | VK_ACCESS_SHADER_READ_BIT, // FIXME
|
|
|
|
.buffer = g_geom.buffer.buffer,
|
2022-05-04 18:23:37 +02:00
|
|
|
.offset = 0, // FIXME
|
|
|
|
.size = VK_WHOLE_SIZE, // FIXME
|
|
|
|
} };
|
|
|
|
vkCmdPipelineBarrier(cmdbuf,
|
|
|
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
2022-05-14 22:36:33 +02:00
|
|
|
//VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR,
|
|
|
|
VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR,
|
2022-05-04 18:23:37 +02:00
|
|
|
0, 0, NULL, ARRAYSIZE(bmb), bmb, 0, NULL);
|
|
|
|
}
|
2022-02-21 01:00:33 +01:00
|
|
|
model->ray_model = VK_RayModelCreate(cmdbuf, args);
|
2021-05-24 20:14:03 +02:00
|
|
|
return !!model->ray_model;
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO pre-bake optimal draws
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void VK_RenderModelDestroy( vk_render_model_t* model ) {
|
2021-07-04 20:18:28 +02:00
|
|
|
if (vk_core.rtx && (g_render_state.current_frame_is_ray_traced || !model->dynamic)) {
|
2021-05-24 20:14:03 +02:00
|
|
|
VK_RayModelDestroy(model->ray_model);
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-27 19:21:06 +02:00
|
|
|
void VK_RenderModelDraw( const cl_entity_t *ent, vk_render_model_t* model ) {
|
2021-04-07 21:11:20 +02:00
|
|
|
int current_texture = -1;
|
2021-08-11 20:43:33 +02:00
|
|
|
int element_count = 0;
|
2021-04-07 21:11:20 +02:00
|
|
|
int index_offset = -1;
|
2021-07-04 21:48:32 +02:00
|
|
|
int vertex_offset = 0;
|
2021-04-07 21:11:20 +02:00
|
|
|
|
2021-07-04 20:18:28 +02:00
|
|
|
if (g_render_state.current_frame_is_ray_traced) {
|
2021-10-27 19:21:06 +02:00
|
|
|
VK_RayFrameAddModel(model->ray_model, model, (const matrix3x4*)g_render_state.model, g_render_state.dirty_uniform_data.color, ent ? ent->curstate.rendercolor : (color24){255,255,255});
|
2021-06-07 07:46:04 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
drawCmdPushDebugLabelBegin( model->debug_name );
|
2021-08-11 20:43:33 +02:00
|
|
|
|
2021-04-07 21:11:20 +02:00
|
|
|
for (int i = 0; i < model->num_geometries; ++i) {
|
|
|
|
const vk_render_geometry_t *geom = model->geometries + i;
|
2021-08-15 20:02:57 +02:00
|
|
|
const qboolean split = current_texture != geom->texture
|
2021-08-11 20:43:33 +02:00
|
|
|
|| vertex_offset != geom->vertex_offset
|
|
|
|
|| (index_offset + element_count) != geom->index_offset;
|
|
|
|
|
|
|
|
// We only support indexed geometry
|
|
|
|
ASSERT(geom->index_offset >= 0);
|
|
|
|
|
2021-04-07 21:11:20 +02:00
|
|
|
if (geom->texture < 0)
|
|
|
|
continue;
|
|
|
|
|
2021-08-11 20:43:33 +02:00
|
|
|
if (split) {
|
|
|
|
if (element_count) {
|
2021-08-15 20:02:57 +02:00
|
|
|
render_draw_t draw = {
|
2021-06-23 19:40:37 +02:00
|
|
|
.lightmap = tglob.lightmapTextures[0], // FIXME there can be more than one lightmap textures
|
2021-04-07 21:11:20 +02:00
|
|
|
.texture = current_texture,
|
|
|
|
.render_mode = model->render_mode,
|
2021-08-11 20:43:33 +02:00
|
|
|
.element_count = element_count,
|
2021-07-04 21:48:32 +02:00
|
|
|
.vertex_offset = vertex_offset,
|
2021-04-07 21:11:20 +02:00
|
|
|
.index_offset = index_offset,
|
|
|
|
};
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
drawCmdPushDraw( &draw );
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
current_texture = geom->texture;
|
2021-08-11 20:43:33 +02:00
|
|
|
index_offset = geom->index_offset;
|
2021-07-04 21:48:32 +02:00
|
|
|
vertex_offset = geom->vertex_offset;
|
2021-08-11 20:43:33 +02:00
|
|
|
element_count = 0;
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure that all surfaces are concatenated in buffers
|
2021-08-11 20:43:33 +02:00
|
|
|
ASSERT(index_offset + element_count == geom->index_offset);
|
|
|
|
element_count += geom->element_count;
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 20:43:33 +02:00
|
|
|
if (element_count) {
|
2021-04-07 21:11:20 +02:00
|
|
|
const render_draw_t draw = {
|
|
|
|
.lightmap = tglob.lightmapTextures[0],
|
|
|
|
.texture = current_texture,
|
|
|
|
.render_mode = model->render_mode,
|
2021-08-11 20:43:33 +02:00
|
|
|
.element_count = element_count,
|
2021-07-04 21:48:32 +02:00
|
|
|
.vertex_offset = vertex_offset,
|
2021-04-07 21:11:20 +02:00
|
|
|
.index_offset = index_offset,
|
|
|
|
};
|
|
|
|
|
2021-08-15 20:02:57 +02:00
|
|
|
drawCmdPushDraw( &draw );
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
2021-08-15 20:02:57 +02:00
|
|
|
|
|
|
|
drawCmdPushDebugLabelEnd();
|
2021-04-07 21:11:20 +02:00
|
|
|
}
|
2021-04-24 21:53:42 +02:00
|
|
|
|
|
|
|
#define MAX_DYNAMIC_GEOMETRY 256
|
|
|
|
|
|
|
|
static struct {
|
|
|
|
vk_render_model_t model;
|
|
|
|
vk_render_geometry_t geometries[MAX_DYNAMIC_GEOMETRY];
|
|
|
|
} g_dynamic_model = {0};
|
|
|
|
|
2021-09-14 19:20:15 +02:00
|
|
|
void VK_RenderModelDynamicBegin( int render_mode, const char *debug_name_fmt, ... ) {
|
|
|
|
va_list argptr;
|
|
|
|
va_start( argptr, debug_name_fmt );
|
|
|
|
vsnprintf(g_dynamic_model.model.debug_name, sizeof(g_dynamic_model.model.debug_name), debug_name_fmt, argptr );
|
|
|
|
va_end( argptr );
|
|
|
|
|
2021-09-14 20:44:19 +02:00
|
|
|
ASSERT(!g_dynamic_model.model.geometries);
|
2021-04-24 21:53:42 +02:00
|
|
|
g_dynamic_model.model.geometries = g_dynamic_model.geometries;
|
|
|
|
g_dynamic_model.model.num_geometries = 0;
|
|
|
|
g_dynamic_model.model.render_mode = render_mode;
|
|
|
|
}
|
|
|
|
void VK_RenderModelDynamicAddGeometry( const vk_render_geometry_t *geom ) {
|
|
|
|
ASSERT(g_dynamic_model.model.geometries);
|
|
|
|
if (g_dynamic_model.model.num_geometries == MAX_DYNAMIC_GEOMETRY) {
|
2021-10-24 21:06:17 +02:00
|
|
|
ERROR_THROTTLED(10, "Ran out of dynamic model geometry slots for model %s", g_dynamic_model.model.debug_name);
|
2021-04-24 21:53:42 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_dynamic_model.geometries[g_dynamic_model.model.num_geometries++] = *geom;
|
|
|
|
}
|
|
|
|
void VK_RenderModelDynamicCommit( void ) {
|
|
|
|
ASSERT(g_dynamic_model.model.geometries);
|
|
|
|
|
|
|
|
if (g_dynamic_model.model.num_geometries > 0) {
|
|
|
|
g_dynamic_model.model.dynamic = true;
|
2022-02-21 01:00:33 +01:00
|
|
|
VK_RenderModelInit( vk_frame.cmdbuf, &g_dynamic_model.model );
|
2021-10-27 19:21:06 +02:00
|
|
|
VK_RenderModelDraw( NULL, &g_dynamic_model.model );
|
2021-04-24 21:53:42 +02:00
|
|
|
}
|
|
|
|
|
2021-09-14 19:20:15 +02:00
|
|
|
g_dynamic_model.model.debug_name[0] = '\0';
|
2021-04-24 21:53:42 +02:00
|
|
|
g_dynamic_model.model.geometries = NULL;
|
|
|
|
}
|