Merge pull request #26 from w23/better-buffers
join alloc+lock operations on buffer init also disable ci results uploading, this is at the very best useless
This commit is contained in:
commit
31520a7c0b
|
@ -58,15 +58,15 @@ jobs:
|
|||
- name: Build engine
|
||||
run: bash scripts/gha/build_${{ matrix.targetos }}.sh
|
||||
|
||||
- name: Upload engine (android)
|
||||
if: matrix.targetos == 'android'
|
||||
run: bash scripts/continious_upload.sh xashdroid-${{ matrix.targetarch }}.apk
|
||||
- name: Upload engine (motomagx)
|
||||
if: matrix.targetos == 'motomagx'
|
||||
run: bash scripts/continious_upload.sh xash3d-fwgs-magx.7z
|
||||
- name: Upload engine (linux)
|
||||
if: matrix.targetos == 'linux'
|
||||
run: bash scripts/continious_upload.sh xash3d-fwgs-${{ matrix.targetarch }}.AppImage xashds-linux-${{ matrix.targetarch }}
|
||||
- name: Upload engine (windows)
|
||||
if: matrix.targetos == 'win32'
|
||||
run: bash scripts/continious_upload.sh xash3d-fwgs-win32-${{ matrix.targetarch }}.7z xash3d-fwgs-vc2008-sln-${{ matrix.targetarch }}.7z
|
||||
# - name: Upload engine (android)
|
||||
# if: matrix.targetos == 'android'
|
||||
# run: bash scripts/continious_upload.sh xashdroid-${{ matrix.targetarch }}.apk
|
||||
# - name: Upload engine (motomagx)
|
||||
# if: matrix.targetos == 'motomagx'
|
||||
# run: bash scripts/continious_upload.sh xash3d-fwgs-magx.7z
|
||||
# - name: Upload engine (linux)
|
||||
# if: matrix.targetos == 'linux'
|
||||
# run: bash scripts/continious_upload.sh xash3d-fwgs-${{ matrix.targetarch }}.AppImage xashds-linux-${{ matrix.targetarch }}
|
||||
# - name: Upload engine (windows)
|
||||
# if: matrix.targetos == 'win32'
|
||||
# run: bash scripts/continious_upload.sh xash3d-fwgs-win32-${{ matrix.targetarch }}.7z xash3d-fwgs-vc2008-sln-${{ matrix.targetarch }}.7z
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
## 2021-08-07, E124
|
||||
- [x] anisotropic texture sampling
|
||||
- [x] studio model lighting prep
|
||||
- [x] copy over R_LightVec from GL renderer
|
||||
- [x] add per-vertex color attribute
|
||||
- [x] support per-vertex colors
|
||||
- [x] disable lightmaps, or use white texture for it instead
|
||||
|
||||
# Next
|
||||
- [ ] restore render debug labels
|
||||
- [ ] rtx: simple convolution denoise (bilateral?)
|
||||
- [ ] rtx: split ray tracing into modules: pipeline mgmt, buffer mgmt
|
||||
- [ ] rtx: better light culling: normal, bsp visibility, light volumes and intensity, sort by intensity, etc
|
||||
- [ ] rtx: cluster dlights
|
||||
|
@ -14,15 +8,18 @@
|
|||
Split into 2 buffers:
|
||||
struct LightCluster { uint16 offset, length; }
|
||||
uint8_t data[];
|
||||
- [ ] studio models: fix lighting: should have white texture instead of lightmap OR we could write nearest surface lightmap coords to fake light
|
||||
- [ ] make it look correct lol
|
||||
|
||||
# Planned
|
||||
- [ ] make a list of all possible materials, categorize them and figure out what to do
|
||||
- [ ] possibly split vk_render into (a) rendering/pipeline, (b) buffer management/allocation, (c) render state
|
||||
- [ ] restore draw call concatenation; brush geoms are generated in a way that makes concatenating them impossible
|
||||
- [ ] rtx: light styles: need static lights data, not clear how and what to do
|
||||
- [ ] studio models: fix lighting: should have white texture instead of lightmap OR we could write nearest surface lightmap coords to fake light
|
||||
- [ ] make it look correct lol
|
||||
- [ ] studio model types:
|
||||
- [x] normal
|
||||
- [ ] float
|
||||
- [ ] chrome
|
||||
- [ ] simplify buffer api: do alloc+lock as a single op
|
||||
- [ ] more beams types
|
||||
- [ ] more particle types
|
||||
- [ ] rtx: better mip lods: there's a weird math that operates on fov degrees (not radians) that we copypasted from ray tracing gems 2 chapter 7. When the book is available, get through the math and figure this out.
|
||||
|
@ -39,9 +36,7 @@
|
|||
- [ ] rtx: coalesce all these buffers
|
||||
- [ ] crash in PM_RecursiveHullCheck
|
||||
- [ ] rtx: entity lights
|
||||
- [ ] rtx: light styles
|
||||
- [ ] run under asan
|
||||
- [ ] rtx: simple convolution denoise (bilateral?)
|
||||
- [ ] rtx: emissive beams
|
||||
- [ ] rtx: emissive particles
|
||||
- [ ] rtx: better random
|
||||
|
@ -64,7 +59,6 @@
|
|||
- [ ] rtx: cull light sources (dlights and light textures) using bsp
|
||||
- [ ] enable entity-parsed lights by lightstyles
|
||||
- [ ] dlight for flashlight seems to be broken
|
||||
- [ ] restore render debug labels
|
||||
- [ ] make 2nd commad buffer for resource upload
|
||||
- [ ] fix sprite blending; there are commented out functions that we really need (see tunnel before the helicopter in the very beginning)
|
||||
- [ ] fix projection matrix differences w/ gl render
|
||||
|
@ -314,3 +308,14 @@
|
|||
|
||||
## 2021-08-02..04, E122-123
|
||||
- [x] mipmaps
|
||||
|
||||
## 2021-08-07, E124
|
||||
- [x] anisotropic texture sampling
|
||||
- [x] studio model lighting prep
|
||||
- [x] copy over R_LightVec from GL renderer
|
||||
- [x] add per-vertex color attribute
|
||||
- [x] support per-vertex colors
|
||||
- [x] disable lightmaps, or use white texture for it instead
|
||||
|
||||
## 2021-08-11, E125
|
||||
- [x] simplify buffer api: do alloc+lock as a single op
|
|
@ -163,8 +163,7 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
|
|||
beamseg_t curSeg;
|
||||
int total_vertices = 0;
|
||||
int total_indices = 0;
|
||||
vk_buffer_handle_t vertex_buffer, index_buffer;
|
||||
vk_buffer_lock_t vertex_lock, index_lock;
|
||||
xvk_render_buffer_allocation_t vertex_buffer, index_buffer;
|
||||
vk_vertex_t *dst_vtx;
|
||||
uint16_t *dst_idx;
|
||||
|
||||
|
@ -224,19 +223,17 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
|
|||
total_indices = (total_vertices - 2) * 3; // STRIP unrolled into LIST (TODO get rid of this)
|
||||
ASSERT(total_vertices < UINT16_MAX );
|
||||
|
||||
vertex_buffer = VK_RenderBufferAlloc( sizeof(vk_vertex_t), total_vertices, LifetimeSingleFrame );
|
||||
index_buffer = VK_RenderBufferAlloc( sizeof(uint16_t), total_indices, LifetimeSingleFrame );
|
||||
if (vertex_buffer == InvalidHandle || index_buffer == InvalidHandle)
|
||||
vertex_buffer = XVK_RenderBufferAllocAndLock( sizeof(vk_vertex_t), total_vertices );
|
||||
index_buffer = XVK_RenderBufferAllocAndLock( sizeof(uint16_t), total_indices );
|
||||
if (!vertex_buffer.ptr || !index_buffer.ptr)
|
||||
{
|
||||
// TODO should we free one of the above if it still succeeded?
|
||||
gEngine.Con_Printf(S_ERROR "Ran out of buffer space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vertex_lock = VK_RenderBufferLock( vertex_buffer );
|
||||
index_lock = VK_RenderBufferLock( index_buffer );
|
||||
dst_vtx = vertex_lock.ptr;
|
||||
dst_idx = index_lock.ptr;
|
||||
dst_vtx = vertex_buffer.ptr;
|
||||
dst_idx = index_buffer.ptr;
|
||||
|
||||
// specify all the segments.
|
||||
for( i = 0; i < segments; i++ )
|
||||
|
@ -380,8 +377,8 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
|
|||
}
|
||||
}
|
||||
|
||||
VK_RenderBufferUnlock( index_buffer );
|
||||
VK_RenderBufferUnlock( vertex_buffer );
|
||||
XVK_RenderBufferUnlock( index_buffer.buffer );
|
||||
XVK_RenderBufferUnlock( vertex_buffer.buffer );
|
||||
|
||||
{
|
||||
const vk_render_geometry_t geometry = {
|
||||
|
@ -389,12 +386,10 @@ static void R_DrawSegs( vec3_t source, vec3_t delta, float width, float scale, f
|
|||
.material = kXVkMaterialDiffuse,
|
||||
|
||||
.vertex_count = total_vertices,
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.vertex_offset = 0,
|
||||
.vertex_offset = vertex_buffer.buffer.unit.offset,
|
||||
|
||||
.element_count = total_indices,
|
||||
.index_offset = 0,
|
||||
.index_buffer = index_buffer,
|
||||
.index_offset = index_buffer.buffer.unit.offset,
|
||||
};
|
||||
|
||||
// FIXME .emissive = { color[0], color[1], color[2] },
|
||||
|
|
|
@ -79,8 +79,7 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
|
|||
glpoly_t *p;
|
||||
int i;
|
||||
int num_vertices = 0, num_indices = 0;
|
||||
vk_buffer_handle_t vertex_buffer, index_buffer = InvalidHandle;
|
||||
vk_buffer_lock_t vertex_lock, index_lock;
|
||||
xvk_render_buffer_allocation_t vertex_buffer, index_buffer = {0};
|
||||
int vertex_offset = 0;
|
||||
vk_vertex_t *gpu_vertices;
|
||||
uint16_t *indices;
|
||||
|
@ -108,20 +107,17 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
|
|||
num_indices += triangles * 3;
|
||||
}
|
||||
|
||||
vertex_buffer = VK_RenderBufferAlloc( sizeof(vk_vertex_t), num_vertices, LifetimeSingleFrame );
|
||||
index_buffer = VK_RenderBufferAlloc( sizeof(uint16_t), num_indices, LifetimeSingleFrame );
|
||||
if (vertex_buffer == InvalidHandle || index_buffer == InvalidHandle)
|
||||
vertex_buffer = XVK_RenderBufferAllocAndLock( sizeof(vk_vertex_t), num_vertices );
|
||||
index_buffer = XVK_RenderBufferAllocAndLock( sizeof(uint16_t), num_indices );
|
||||
if (vertex_buffer.ptr == NULL || index_buffer.ptr == NULL)
|
||||
{
|
||||
// TODO should we free one of the above if it still succeeded?
|
||||
gEngine.Con_Printf(S_ERROR "Ran out of buffer space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vertex_lock = VK_RenderBufferLock( vertex_buffer );
|
||||
index_lock = VK_RenderBufferLock( index_buffer );
|
||||
|
||||
gpu_vertices = vertex_lock.ptr;
|
||||
indices = index_lock.ptr;
|
||||
gpu_vertices = vertex_buffer.ptr;
|
||||
indices = index_buffer.ptr;
|
||||
|
||||
for( p = warp->polys; p; p = p->next )
|
||||
{
|
||||
|
@ -189,7 +185,8 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
|
|||
|
||||
if( reverse )
|
||||
v -= VERTEXSIZE;
|
||||
else v += VERTEXSIZE;
|
||||
else
|
||||
v += VERTEXSIZE;
|
||||
}
|
||||
|
||||
#ifdef WATER_NORMALS
|
||||
|
@ -202,8 +199,8 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
|
|||
vertex_offset += p->numverts;
|
||||
}
|
||||
|
||||
VK_RenderBufferUnlock( vertex_buffer );
|
||||
VK_RenderBufferUnlock( index_buffer );
|
||||
XVK_RenderBufferUnlock( vertex_buffer.buffer );
|
||||
XVK_RenderBufferUnlock( index_buffer.buffer );
|
||||
|
||||
// Render
|
||||
{
|
||||
|
@ -212,12 +209,10 @@ static void EmitWaterPolys( const cl_entity_t *ent, const msurface_t *warp, qboo
|
|||
.material = kXVkMaterialWater,
|
||||
|
||||
.vertex_count = num_vertices,
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.vertex_offset = 0,
|
||||
.vertex_offset = vertex_buffer.buffer.unit.offset,
|
||||
|
||||
.element_count = num_indices,
|
||||
.index_offset = 0,
|
||||
.index_buffer = index_buffer,
|
||||
.index_offset = index_buffer.buffer.unit.offset,
|
||||
};
|
||||
|
||||
VK_RenderModelDynamicAddGeometry( &geometry );
|
||||
|
@ -432,25 +427,22 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
|||
vk_brush_model_t *bmodel = mod->cache.data;
|
||||
uint32_t vertex_offset = 0;
|
||||
int num_geometries = 0;
|
||||
vk_buffer_handle_t vertex_buffer, index_buffer;
|
||||
vk_buffer_lock_t vertex_lock, index_lock;
|
||||
xvk_render_buffer_allocation_t vertex_buffer, index_buffer;
|
||||
vk_vertex_t *bvert = NULL;
|
||||
uint16_t *bind = NULL;
|
||||
uint32_t index_offset = 0;
|
||||
|
||||
vertex_buffer = VK_RenderBufferAlloc( sizeof(vk_vertex_t), sizes.num_vertices, LifetimeMap );
|
||||
index_buffer = VK_RenderBufferAlloc( sizeof(uint16_t), sizes.num_indices, LifetimeMap );
|
||||
if (vertex_buffer == InvalidHandle || index_buffer == InvalidHandle)
|
||||
{
|
||||
// TODO should we free one of the above if it still succeeded?
|
||||
vertex_buffer = XVK_RenderBufferAllocAndLock( sizeof(vk_vertex_t), sizes.num_vertices );
|
||||
index_buffer = XVK_RenderBufferAllocAndLock( sizeof(uint16_t), sizes.num_indices );
|
||||
if (vertex_buffer.ptr == NULL || index_buffer.ptr == NULL) {
|
||||
gEngine.Con_Printf(S_ERROR "Ran out of buffer space\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
vertex_lock = VK_RenderBufferLock( vertex_buffer );
|
||||
index_lock = VK_RenderBufferLock( index_buffer );
|
||||
bvert = vertex_lock.ptr;
|
||||
bind = index_lock.ptr;
|
||||
bvert = vertex_buffer.ptr;
|
||||
bind = index_buffer.ptr;
|
||||
|
||||
index_offset = index_buffer.buffer.unit.offset;
|
||||
|
||||
// Load sorted by gl_texturenum
|
||||
for (int t = 0; t <= sizes.max_texture_id; ++t)
|
||||
|
@ -484,11 +476,9 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
|||
model_geometry->surf = surf;
|
||||
model_geometry->texture = t;
|
||||
|
||||
model_geometry->vertex_buffer = vertex_buffer;
|
||||
model_geometry->vertex_offset = vertex_offset;
|
||||
model_geometry->vertex_offset = vertex_buffer.buffer.unit.offset + vertex_offset;
|
||||
model_geometry->vertex_count = surf->numedges;
|
||||
|
||||
model_geometry->index_buffer = index_buffer;
|
||||
model_geometry->index_offset = index_offset;
|
||||
|
||||
if( FBitSet( surf->flags, SURF_DRAWSKY )) {
|
||||
|
@ -553,8 +543,8 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
|||
}
|
||||
}
|
||||
|
||||
VK_RenderBufferUnlock( index_buffer );
|
||||
VK_RenderBufferUnlock( vertex_buffer );
|
||||
XVK_RenderBufferUnlock( index_buffer.buffer );
|
||||
XVK_RenderBufferUnlock( vertex_buffer.buffer );
|
||||
|
||||
ASSERT(sizes.num_surfaces == num_geometries);
|
||||
bmodel->render_model.num_geometries = num_geometries;
|
||||
|
|
|
@ -425,7 +425,7 @@ void R_EndFrame( void )
|
|||
// retain temporary (SingleFrame) buffer contents for longer, until all users are done.
|
||||
// (this probably means that we should really have some kind of refcount going on...)
|
||||
// For now we can just erase these buffers now because of sync with fence
|
||||
VK_RenderBufferClearFrame();
|
||||
XVK_RenderBufferFrameClear();
|
||||
|
||||
g_frame.swapchain_image_index = -1;
|
||||
}
|
||||
|
|
|
@ -179,8 +179,6 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
|
|||
for (int i = 0; i < args.model->num_geometries; ++i) {
|
||||
vk_render_geometry_t *mg = args.model->geometries + i;
|
||||
const uint32_t prim_count = mg->element_count / 3;
|
||||
const uint32_t vertex_offset = mg->vertex_offset + VK_RenderBufferGetOffsetInUnits(mg->vertex_buffer);
|
||||
const uint32_t index_offset = mg->index_buffer == InvalidHandle ? UINT32_MAX : (mg->index_offset + VK_RenderBufferGetOffsetInUnits(mg->index_buffer));
|
||||
|
||||
max_prims += prim_count;
|
||||
geom_max_prim_counts[i] = prim_count;
|
||||
|
@ -192,7 +190,7 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
|
|||
.geometry.triangles =
|
||||
(VkAccelerationStructureGeometryTrianglesDataKHR){
|
||||
.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR,
|
||||
.indexType = mg->index_buffer == InvalidHandle ? VK_INDEX_TYPE_NONE_KHR : VK_INDEX_TYPE_UINT16,
|
||||
.indexType = VK_INDEX_TYPE_UINT16,
|
||||
.maxVertex = mg->vertex_count,
|
||||
.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT,
|
||||
.vertexStride = sizeof(vk_vertex_t),
|
||||
|
@ -209,12 +207,12 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
|
|||
|
||||
geom_build_ranges[i] = (VkAccelerationStructureBuildRangeInfoKHR) {
|
||||
.primitiveCount = prim_count,
|
||||
.primitiveOffset = index_offset == UINT32_MAX ? 0 : index_offset * sizeof(uint16_t),
|
||||
.firstVertex = vertex_offset,
|
||||
.primitiveOffset = mg->index_offset * sizeof(uint16_t),
|
||||
.firstVertex = mg->vertex_offset,
|
||||
};
|
||||
|
||||
kusochki[i].vertex_offset = vertex_offset;
|
||||
kusochki[i].index_offset = index_offset;
|
||||
kusochki[i].vertex_offset = mg->vertex_offset;
|
||||
kusochki[i].index_offset = mg->index_offset;
|
||||
kusochki[i].triangles = prim_count;
|
||||
|
||||
kusochki[i].texture = mg->texture;
|
||||
|
|
|
@ -23,15 +23,6 @@ typedef struct {
|
|||
vec4_t color;
|
||||
} uniform_data_t;
|
||||
|
||||
typedef struct vk_buffer_alloc_s {
|
||||
// TODO uint32_t sequence
|
||||
uint32_t unit_size; // if 0 then this alloc slot is free
|
||||
uint32_t buffer_offset_in_units;
|
||||
uint32_t count;
|
||||
qboolean locked;
|
||||
vk_lifetime_t lifetime;
|
||||
} vk_buffer_alloc_t;
|
||||
|
||||
// TODO estimate
|
||||
#define MAX_ALLOCS 1024
|
||||
|
||||
|
@ -40,15 +31,11 @@ static struct {
|
|||
VkPipeline pipelines[kRenderTransAdd + 1];
|
||||
|
||||
vk_buffer_t buffer;
|
||||
vk_ring_buffer_t buffer_alloc;
|
||||
vk_ring_buffer_t buffer_alloc_ring;
|
||||
|
||||
vk_buffer_t uniform_buffer;
|
||||
uint32_t ubo_align;
|
||||
|
||||
vk_buffer_alloc_t allocs[MAX_ALLOCS];
|
||||
int allocs_free[MAX_ALLOCS];
|
||||
int num_free_allocs;
|
||||
|
||||
struct {
|
||||
vec3_t origin, color;
|
||||
} static_lights[32];
|
||||
|
@ -233,14 +220,6 @@ static qboolean createPipelines( void )
|
|||
return true;
|
||||
}
|
||||
|
||||
static void resetAllocFreeList( void ) {
|
||||
g_render.num_free_allocs = MAX_ALLOCS;
|
||||
for (int i = 0; i < MAX_ALLOCS; ++i) {
|
||||
g_render.allocs_free[i] = MAX_ALLOCS - i - 1;
|
||||
g_render.allocs[i].unit_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32_t num_lights, pad[3];
|
||||
struct {
|
||||
|
@ -251,8 +230,7 @@ typedef struct {
|
|||
|
||||
qboolean VK_RenderInit( void )
|
||||
{
|
||||
// TODO Better estimates
|
||||
const uint32_t vertex_buffer_size = MAX_BUFFER_VERTICES * sizeof(float) * (3 + 3 + 2 + 2);
|
||||
const uint32_t vertex_buffer_size = MAX_BUFFER_VERTICES * sizeof(vk_vertex_t);
|
||||
const uint32_t index_buffer_size = MAX_BUFFER_INDICES * sizeof(uint16_t);
|
||||
uint32_t uniform_unit_size;
|
||||
|
||||
|
@ -305,9 +283,7 @@ qboolean VK_RenderInit( void )
|
|||
if (!createPipelines())
|
||||
return false;
|
||||
|
||||
resetAllocFreeList();
|
||||
|
||||
g_render.buffer_alloc.size = g_render.buffer.size;
|
||||
g_render.buffer_alloc_ring.size = g_render.buffer.size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -322,123 +298,51 @@ void VK_RenderShutdown( void )
|
|||
destroyBuffer( &g_render.uniform_buffer );
|
||||
}
|
||||
|
||||
vk_buffer_handle_t VK_RenderBufferAlloc( uint32_t unit_size, uint32_t count, vk_lifetime_t lifetime )
|
||||
{
|
||||
xvk_render_buffer_allocation_t XVK_RenderBufferAllocAndLock( uint32_t unit_size, uint32_t count ) {
|
||||
const uint32_t alloc_size = unit_size * count;
|
||||
uint32_t offset;
|
||||
vk_buffer_alloc_t *alloc;
|
||||
vk_buffer_handle_t handle = InvalidHandle;
|
||||
xvk_render_buffer_allocation_t retval = {0};
|
||||
|
||||
// FIXME long lifetimes are not supported yet
|
||||
ASSERT(lifetime != LifetimeLong);
|
||||
ASSERT(unit_size > 0);
|
||||
|
||||
if (!g_render.num_free_allocs) {
|
||||
gEngine.Con_Printf(S_ERROR "Cannot allocate buffer, allocs count exhausted\n" );
|
||||
return InvalidHandle;
|
||||
}
|
||||
|
||||
offset = VK_RingBuffer_Alloc(&g_render.buffer_alloc, alloc_size, unit_size);
|
||||
offset = VK_RingBuffer_Alloc(&g_render.buffer_alloc_ring, alloc_size, unit_size);
|
||||
|
||||
if (offset == AllocFailed) {
|
||||
gEngine.Con_Printf(S_ERROR "Cannot allocate %u bytes aligned at %u from buffer; only %u are left",
|
||||
alloc_size, unit_size, g_render.buffer_alloc.free);
|
||||
return InvalidHandle;
|
||||
alloc_size, unit_size, g_render.buffer_alloc_ring.free);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// TODO bake sequence number into handle (to detect buffer lifetime misuse)
|
||||
handle = g_render.allocs_free[--g_render.num_free_allocs];
|
||||
alloc = g_render.allocs + handle;
|
||||
ASSERT(alloc->unit_size == 0);
|
||||
retval.buffer.unit.size = unit_size;
|
||||
retval.buffer.unit.count = count;
|
||||
retval.buffer.unit.offset = offset / unit_size;
|
||||
retval.ptr = ((byte*)g_render.buffer.mapped) + offset;
|
||||
|
||||
alloc->buffer_offset_in_units = offset / unit_size;
|
||||
alloc->unit_size = unit_size;
|
||||
alloc->lifetime = lifetime;
|
||||
alloc->count = count;
|
||||
|
||||
return handle;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static vk_buffer_alloc_t *getBufferFromHandle( vk_buffer_handle_t handle )
|
||||
{
|
||||
vk_buffer_alloc_t *alloc;
|
||||
|
||||
ASSERT(handle >= 0);
|
||||
ASSERT(handle < MAX_ALLOCS);
|
||||
|
||||
// TODO check sequence number
|
||||
alloc = g_render.allocs + handle;
|
||||
ASSERT(alloc->unit_size != 0);
|
||||
|
||||
return alloc;
|
||||
void XVK_RenderBufferUnlock( xvk_render_buffer_t handle ) {
|
||||
// TODO check whether we need to upload something from staging, etc
|
||||
}
|
||||
|
||||
vk_buffer_lock_t VK_RenderBufferLock( vk_buffer_handle_t handle )
|
||||
{
|
||||
vk_buffer_lock_t ret = {0};
|
||||
vk_buffer_alloc_t *alloc = getBufferFromHandle( handle );
|
||||
ASSERT(!alloc->locked);
|
||||
alloc->locked = true;
|
||||
|
||||
ret.unit_size = alloc->unit_size;
|
||||
ret.count = alloc->count;
|
||||
ret.ptr = ((byte*)g_render.buffer.mapped) + alloc->unit_size * alloc->buffer_offset_in_units;
|
||||
|
||||
return ret;
|
||||
void XVK_RenderBufferMapFreeze( void ) {
|
||||
VK_RingBuffer_Fix(&g_render.buffer_alloc_ring);
|
||||
}
|
||||
|
||||
void VK_RenderBufferUnlock( vk_buffer_handle_t handle )
|
||||
{
|
||||
vk_buffer_alloc_t *alloc = getBufferFromHandle( handle );
|
||||
ASSERT(alloc->locked);
|
||||
alloc->locked = false;
|
||||
|
||||
// TODO upload from staging to gpumem
|
||||
}
|
||||
|
||||
uint32_t VK_RenderBufferGetOffsetInUnits( vk_buffer_handle_t handle )
|
||||
{
|
||||
const vk_buffer_alloc_t *alloc = getBufferFromHandle( handle );
|
||||
return alloc->buffer_offset_in_units;
|
||||
}
|
||||
|
||||
// Free all LifetimeSingleFrame resources
|
||||
void VK_RenderBufferClearFrame( void )
|
||||
{
|
||||
VK_RingBuffer_ClearFrame(&g_render.buffer_alloc);
|
||||
|
||||
for (int i = 0; i < MAX_ALLOCS; ++i) {
|
||||
vk_buffer_alloc_t *alloc = g_render.allocs + i;
|
||||
|
||||
if (!alloc->unit_size)
|
||||
continue;
|
||||
|
||||
if (alloc->lifetime != LifetimeSingleFrame)
|
||||
continue;
|
||||
|
||||
alloc->unit_size = 0;
|
||||
g_render.allocs_free[g_render.num_free_allocs++] = i;
|
||||
ASSERT(g_render.num_free_allocs <= MAX_ALLOCS);
|
||||
}
|
||||
}
|
||||
|
||||
// Free all LifetimeMap resources
|
||||
void VK_RenderBufferClearMap( void )
|
||||
{
|
||||
VK_RingBuffer_Clear(&g_render.buffer_alloc);
|
||||
void XVK_RenderBufferMapClear( void ) {
|
||||
VK_RingBuffer_Clear(&g_render.buffer_alloc_ring);
|
||||
g_render.num_static_lights = 0;
|
||||
resetAllocFreeList();
|
||||
}
|
||||
|
||||
void VK_RenderMapLoadEnd( void )
|
||||
{
|
||||
VK_RingBuffer_Fix(&g_render.buffer_alloc);
|
||||
void XVK_RenderBufferFrameClear( /*int frame_id*/void ) {
|
||||
VK_RingBuffer_ClearFrame(&g_render.buffer_alloc_ring);
|
||||
}
|
||||
|
||||
void VK_RenderBufferPrintStats( void )
|
||||
{
|
||||
void XVK_RenderBufferPrintStats( void ) {
|
||||
// TODO get alignment holes size
|
||||
gEngine.Con_Reportf("Buffer usage: %uKiB of (%uKiB)\n",
|
||||
g_render.buffer_alloc.permanent_size / 1024,
|
||||
g_render.buffer_alloc_ring.permanent_size / 1024,
|
||||
g_render.buffer.size / 1024);
|
||||
}
|
||||
|
||||
|
@ -450,7 +354,6 @@ typedef struct render_draw_s {
|
|||
int render_mode;
|
||||
uint32_t element_count;
|
||||
uint32_t index_offset, vertex_offset;
|
||||
vk_buffer_handle_t index_buffer, vertex_buffer;
|
||||
/* TODO this should be a separate thing? */ struct { float r, g, b; } emissive;
|
||||
} render_draw_t;
|
||||
|
||||
|
@ -564,7 +467,6 @@ static uint32_t allocUniform( uint32_t size, uint32_t alignment ) {
|
|||
|
||||
static void VK_RenderScheduleDraw( const render_draw_t *draw )
|
||||
{
|
||||
const vk_buffer_alloc_t *vertex_buffer = NULL, *index_buffer = NULL;
|
||||
draw_command_t *draw_command;
|
||||
|
||||
ASSERT(draw->render_mode >= 0);
|
||||
|
@ -572,20 +474,6 @@ static void VK_RenderScheduleDraw( const render_draw_t *draw )
|
|||
ASSERT(draw->lightmap >= 0);
|
||||
ASSERT(draw->texture >= 0);
|
||||
|
||||
{
|
||||
vertex_buffer = getBufferFromHandle(draw->vertex_buffer);
|
||||
ASSERT(vertex_buffer);
|
||||
ASSERT(!vertex_buffer->locked);
|
||||
}
|
||||
|
||||
// Index buffer is optional
|
||||
if (draw->index_buffer != InvalidHandle)
|
||||
{
|
||||
index_buffer = getBufferFromHandle(draw->index_buffer);
|
||||
ASSERT(index_buffer);
|
||||
ASSERT(!index_buffer->locked);
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -711,9 +599,6 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf )
|
|||
|
||||
for (int i = 0; i < g_render_state.num_draw_commands; ++i) {
|
||||
const draw_command_t *const draw = g_render_state.draw_commands + i;
|
||||
const vk_buffer_alloc_t *vertex_buffer = getBufferFromHandle( draw->draw.vertex_buffer );
|
||||
const vk_buffer_alloc_t *index_buffer = draw->draw.index_buffer != InvalidHandle ? getBufferFromHandle( draw->draw.index_buffer ) : NULL;
|
||||
const uint32_t vertex_offset = vertex_buffer->buffer_offset_in_units + draw->draw.vertex_offset;
|
||||
|
||||
if (ubo_offset != draw->ubo_offset)
|
||||
{
|
||||
|
@ -738,12 +623,9 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf )
|
|||
vkCmdBindDescriptorSets(vk_core.cb, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 1, 1, &findTexture(texture)->vk.descriptor, 0, NULL);
|
||||
}
|
||||
|
||||
if (draw->draw.index_buffer) {
|
||||
const uint32_t index_offset = index_buffer->buffer_offset_in_units + draw->draw.index_offset;
|
||||
vkCmdDrawIndexed(vk_core.cb, draw->draw.element_count, 1, index_offset, vertex_offset, 0);
|
||||
} else {
|
||||
vkCmdDraw(vk_core.cb, draw->draw.element_count, 1, vertex_offset, 0);
|
||||
}
|
||||
// Only indexed mode is supported
|
||||
ASSERT(draw->draw.index_offset >= 0);
|
||||
vkCmdDrawIndexed(vk_core.cb, draw->draw.element_count, 1, draw->draw.index_offset, draw->draw.vertex_offset, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -847,32 +729,35 @@ void VK_RenderModelDestroy( vk_render_model_t* model ) {
|
|||
|
||||
void VK_RenderModelDraw( vk_render_model_t* model ) {
|
||||
int current_texture = -1;
|
||||
int index_count = 0;
|
||||
int element_count = 0;
|
||||
int index_offset = -1;
|
||||
int vertex_offset = 0;
|
||||
vk_buffer_handle_t vertex_buffer = InvalidHandle;
|
||||
vk_buffer_handle_t index_buffer = InvalidHandle;
|
||||
|
||||
if (g_render_state.current_frame_is_ray_traced) {
|
||||
VK_RayFrameAddModel(model->ray_model, model, (const matrix3x4*)g_render_state.model);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < model->num_geometries; ++i) {
|
||||
const vk_render_geometry_t *geom = model->geometries + i;
|
||||
const qboolean split = current_texture != geom->texture
|
||||
|| vertex_offset != geom->vertex_offset
|
||||
|| (index_offset + element_count) != geom->index_offset;
|
||||
|
||||
// We only support indexed geometry
|
||||
ASSERT(geom->index_offset >= 0);
|
||||
|
||||
if (geom->texture < 0)
|
||||
continue;
|
||||
|
||||
if (current_texture != geom->texture || vertex_buffer != geom->vertex_buffer || index_buffer != geom->index_buffer || vertex_offset != geom->vertex_offset)
|
||||
{
|
||||
if (index_count) {
|
||||
if (split) {
|
||||
if (element_count) {
|
||||
const render_draw_t draw = {
|
||||
.lightmap = tglob.lightmapTextures[0], // FIXME there can be more than one lightmap textures
|
||||
.texture = current_texture,
|
||||
.render_mode = model->render_mode,
|
||||
.element_count = index_count,
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.index_buffer = index_buffer,
|
||||
.element_count = element_count,
|
||||
.vertex_offset = vertex_offset,
|
||||
.index_offset = index_offset,
|
||||
};
|
||||
|
@ -881,28 +766,22 @@ void VK_RenderModelDraw( vk_render_model_t* model ) {
|
|||
}
|
||||
|
||||
current_texture = geom->texture;
|
||||
vertex_buffer = geom->vertex_buffer;
|
||||
index_buffer = geom->index_buffer;
|
||||
index_count = 0;
|
||||
index_offset = -1;
|
||||
index_offset = geom->index_offset;
|
||||
vertex_offset = geom->vertex_offset;
|
||||
element_count = 0;
|
||||
}
|
||||
|
||||
if (index_offset < 0)
|
||||
index_offset = geom->index_offset;
|
||||
// Make sure that all surfaces are concatenated in buffers
|
||||
ASSERT(index_offset + index_count == geom->index_offset);
|
||||
index_count += geom->element_count;
|
||||
ASSERT(index_offset + element_count == geom->index_offset);
|
||||
element_count += geom->element_count;
|
||||
}
|
||||
|
||||
if (index_count) {
|
||||
if (element_count) {
|
||||
const render_draw_t draw = {
|
||||
.lightmap = tglob.lightmapTextures[0],
|
||||
.texture = current_texture,
|
||||
.render_mode = model->render_mode,
|
||||
.element_count = index_count,
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.index_buffer = index_buffer,
|
||||
.element_count = element_count,
|
||||
.vertex_offset = vertex_offset,
|
||||
.index_offset = index_offset,
|
||||
};
|
||||
|
|
|
@ -6,40 +6,34 @@
|
|||
qboolean VK_RenderInit( void );
|
||||
void VK_RenderShutdown( void );
|
||||
|
||||
typedef int vk_buffer_handle_t; // -1 == invalid handle
|
||||
enum { InvalidHandle = -1 };
|
||||
// General buffer usage pattern
|
||||
// 1. alloc (allocates buffer mem, stores allocation data)
|
||||
// 2. (returns void* buf and handle) write to buf
|
||||
// 3. upload and lock (ensures that all this data is in gpu mem, e.g. uploads from staging)
|
||||
// 4. ... use it
|
||||
// 5. free (frame/map end)
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
uint32_t size; // single unit size in bytes
|
||||
uint32_t offset; // offset in units from start of vulkan buffer
|
||||
uint32_t count; // number of units in this allocation
|
||||
} unit;
|
||||
} xvk_render_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
void *ptr;
|
||||
uint32_t unit_size, count;
|
||||
} vk_buffer_lock_t;
|
||||
xvk_render_buffer_t buffer;
|
||||
} xvk_render_buffer_allocation_t;
|
||||
|
||||
typedef enum {
|
||||
LifetimeLong,
|
||||
LifetimeMap,
|
||||
LifetimeSingleFrame,
|
||||
} vk_lifetime_t;
|
||||
xvk_render_buffer_allocation_t XVK_RenderBufferAllocAndLock( uint32_t unit_size, uint32_t count );
|
||||
void XVK_RenderBufferUnlock( xvk_render_buffer_t handle );
|
||||
void XVK_RenderBufferMapFreeze( void ); // Permanently freeze all allocations as map-permanent
|
||||
void XVK_RenderBufferMapClear( void ); // Free the entire buffer for a new map
|
||||
|
||||
// TODO: allocation lifetime with contents validity lifetime?
|
||||
void XVK_RenderBufferFrameClear( /*int frame_id*/void ); // mark data for frame with given id as free (essentially, just forward the ring buffer)
|
||||
|
||||
vk_buffer_handle_t VK_RenderBufferAlloc( uint32_t unit_size, uint32_t count, vk_lifetime_t lifetime );
|
||||
vk_buffer_lock_t VK_RenderBufferLock( vk_buffer_handle_t handle );
|
||||
void VK_RenderBufferUnlock( vk_buffer_handle_t handle );
|
||||
uint32_t VK_RenderBufferGetOffsetInUnits( vk_buffer_handle_t handle );
|
||||
|
||||
// TODO buffer refcount when doing RTX AS updates? need to store buffer handles somewhere between frames
|
||||
|
||||
// Free all LifetimeSingleFrame resources
|
||||
void VK_RenderBufferClearFrame( void );
|
||||
|
||||
// Free all LifetimeMap resources
|
||||
void VK_RenderBufferClearMap( void );
|
||||
|
||||
// Mark map as loaded
|
||||
void VK_RenderMapLoadEnd( void );
|
||||
|
||||
// TODO uploading to GPU mem interface
|
||||
void VK_RenderBufferPrintStats( void );
|
||||
void XVK_RenderBufferPrintStats( void );
|
||||
|
||||
// Set UBO state for next VK_RenderScheduleDraw calls
|
||||
// Why? Xash Ref code is organized in a way where we can't reliably pass this info with
|
||||
|
@ -75,8 +69,7 @@ typedef enum {
|
|||
} XVkMaterialType;
|
||||
|
||||
typedef struct {
|
||||
vk_buffer_handle_t index_buffer, vertex_buffer;
|
||||
uint32_t index_offset, vertex_offset;
|
||||
int index_offset, vertex_offset;
|
||||
|
||||
// TODO can be dynamic
|
||||
int texture;
|
||||
|
|
|
@ -107,7 +107,7 @@ void R_NewMap( void )
|
|||
// TODO should we do something like VK_BrushBeginLoad?
|
||||
VK_BrushStatsClear();
|
||||
|
||||
VK_RenderBufferClearMap();
|
||||
XVK_RenderBufferMapClear();
|
||||
|
||||
if (vk_core.rtx)
|
||||
VK_RayNewMap();
|
||||
|
@ -157,10 +157,10 @@ void R_NewMap( void )
|
|||
|
||||
// TODO should we do something like VK_BrushEndLoad?
|
||||
VK_UploadLightmap();
|
||||
VK_RenderMapLoadEnd();
|
||||
XVK_RenderBufferMapFreeze();
|
||||
XVK_RenderBufferPrintStats();
|
||||
if (vk_core.rtx)
|
||||
VK_RayMapLoadEnd();
|
||||
VK_RenderBufferPrintStats();
|
||||
}
|
||||
|
||||
qboolean R_AddEntity( struct cl_entity_s *clent, int type )
|
||||
|
|
|
@ -649,25 +649,22 @@ qboolean R_SpriteOccluded( cl_entity_t *e, vec3_t origin, float *pscale )
|
|||
static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right, vec3_t v_up, float scale, int texture, int render_mode )
|
||||
{
|
||||
vec3_t point;
|
||||
vk_buffer_handle_t vertex_buffer, index_buffer;
|
||||
vk_buffer_lock_t vertex_lock, index_lock;
|
||||
xvk_render_buffer_allocation_t vertex_buffer, index_buffer;
|
||||
vk_vertex_t *dst_vtx;
|
||||
uint16_t *dst_idx;
|
||||
|
||||
// Get buffer region for vertices and indices
|
||||
vertex_buffer = VK_RenderBufferAlloc( sizeof(vk_vertex_t), 4, LifetimeSingleFrame );
|
||||
index_buffer = VK_RenderBufferAlloc( sizeof(uint16_t), 6, LifetimeSingleFrame );
|
||||
if (vertex_buffer == InvalidHandle || index_buffer == InvalidHandle)
|
||||
vertex_buffer = XVK_RenderBufferAllocAndLock( sizeof(vk_vertex_t), 4 );
|
||||
index_buffer = XVK_RenderBufferAllocAndLock( sizeof(uint16_t), 6 );
|
||||
if (!vertex_buffer.ptr || !index_buffer.ptr)
|
||||
{
|
||||
// TODO should we free one of the above if it still succeeded?
|
||||
gEngine.Con_Printf(S_ERROR "Ran out of buffer space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vertex_lock = VK_RenderBufferLock( vertex_buffer );
|
||||
index_lock = VK_RenderBufferLock( index_buffer );
|
||||
dst_vtx = vertex_lock.ptr;
|
||||
dst_idx = index_lock.ptr;
|
||||
dst_vtx = vertex_buffer.ptr;
|
||||
dst_idx = index_buffer.ptr;
|
||||
|
||||
// FIXME VK r_stats.c_sprite_polys++;
|
||||
|
||||
|
@ -702,8 +699,8 @@ static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right,
|
|||
dst_idx[4] = 2;
|
||||
dst_idx[5] = 3;
|
||||
|
||||
VK_RenderBufferUnlock( index_buffer );
|
||||
VK_RenderBufferUnlock( vertex_buffer );
|
||||
XVK_RenderBufferUnlock( index_buffer.buffer );
|
||||
XVK_RenderBufferUnlock( vertex_buffer.buffer );
|
||||
|
||||
{
|
||||
const vk_render_geometry_t geometry = {
|
||||
|
@ -711,12 +708,10 @@ static void R_DrawSpriteQuad( mspriteframe_t *frame, vec3_t org, vec3_t v_right,
|
|||
.material = kXVkMaterialDiffuse,
|
||||
|
||||
.vertex_count = 4,
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.vertex_offset = 0,
|
||||
.vertex_offset = vertex_buffer.buffer.unit.offset,
|
||||
|
||||
.element_count = 6,
|
||||
.index_offset = 0,
|
||||
.index_buffer = index_buffer,
|
||||
.index_offset = index_buffer.buffer.unit.offset,
|
||||
};
|
||||
|
||||
VK_RenderModelDynamicBegin( "sprite" /* TODO its name */, render_mode );
|
||||
|
|
|
@ -1902,8 +1902,7 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
|
|||
float *lv;
|
||||
int i;
|
||||
int num_vertices = 0, num_indices = 0;
|
||||
vk_buffer_handle_t vertex_buffer, index_buffer;
|
||||
vk_buffer_lock_t vertex_lock, index_lock;
|
||||
xvk_render_buffer_allocation_t vertex_buffer, index_buffer;
|
||||
vk_vertex_t *dst_vtx;
|
||||
uint16_t *dst_idx;
|
||||
uint32_t vertex_offset = 0, index_offset = 0;
|
||||
|
@ -1924,19 +1923,17 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
|
|||
ASSERT(num_indices > 0);
|
||||
|
||||
// Get buffer region for vertices and indices
|
||||
vertex_buffer = VK_RenderBufferAlloc( sizeof(vk_vertex_t), num_vertices, LifetimeSingleFrame );
|
||||
index_buffer = VK_RenderBufferAlloc( sizeof(uint16_t), num_indices, LifetimeSingleFrame );
|
||||
if (vertex_buffer == InvalidHandle || index_buffer == InvalidHandle)
|
||||
vertex_buffer = XVK_RenderBufferAllocAndLock( sizeof(vk_vertex_t), num_vertices );
|
||||
index_buffer = XVK_RenderBufferAllocAndLock( sizeof(uint16_t), num_indices );
|
||||
if (vertex_buffer.ptr == NULL || index_buffer.ptr == NULL)
|
||||
{
|
||||
// TODO should we free one of the above if it still succeeded?
|
||||
gEngine.Con_Printf(S_ERROR "Ran out of buffer space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
vertex_lock = VK_RenderBufferLock( vertex_buffer );
|
||||
index_lock = VK_RenderBufferLock( index_buffer );
|
||||
dst_vtx = vertex_lock.ptr;
|
||||
dst_idx = index_lock.ptr;
|
||||
dst_vtx = vertex_buffer.ptr;
|
||||
dst_idx = index_buffer.ptr;
|
||||
|
||||
// Restore ptricmds and upload vertices
|
||||
ptricmds = ptricmds_initial;
|
||||
|
@ -1948,7 +1945,7 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
|
|||
|
||||
for(int j = 0; j < vertices ; ++j, ++dst_vtx, ptricmds += 4 )
|
||||
{
|
||||
ASSERT((((vk_vertex_t*)vertex_lock.ptr) + vertex_lock.count) > dst_vtx);
|
||||
ASSERT((((vk_vertex_t*)vertex_buffer.ptr) + num_vertices) > dst_vtx);
|
||||
|
||||
VectorCopy(g_studio.verts[ptricmds[0]], dst_vtx->pos);
|
||||
VectorCopy(g_studio.norms[ptricmds[0]], dst_vtx->normal);
|
||||
|
@ -1997,8 +1994,8 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
|
|||
ASSERT(index_offset == num_indices);
|
||||
ASSERT(vertex_offset == num_vertices);
|
||||
|
||||
VK_RenderBufferUnlock( index_buffer );
|
||||
VK_RenderBufferUnlock( vertex_buffer );
|
||||
XVK_RenderBufferUnlock( index_buffer.buffer );
|
||||
XVK_RenderBufferUnlock( vertex_buffer.buffer );
|
||||
|
||||
// Render
|
||||
{
|
||||
|
@ -2007,12 +2004,10 @@ static void R_StudioDrawNormalMesh( short *ptricmds, vec3_t *pstudionorms, float
|
|||
.texture = texture,
|
||||
.material = kXVkMaterialDiffuse,
|
||||
|
||||
.vertex_buffer = vertex_buffer,
|
||||
.vertex_offset = 0,
|
||||
.vertex_offset = vertex_buffer.buffer.unit.offset,
|
||||
.vertex_count = num_vertices,
|
||||
|
||||
.index_buffer = index_buffer,
|
||||
.index_offset = 0,
|
||||
.index_offset = index_buffer.buffer.unit.offset,
|
||||
.element_count = num_indices,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue