[vulkan] Rewrite staging buffer packet handling

It now uses the ring buffer code I wrote for qwaq (and forgot about,
oops) to handle the packets themselves, and the logic for allocating and
freeing space from the buffer is a bit simpler and seems to be more
reliable. The automated test is a bit of a joke now, though, but coming
up with good tests for it... However, nq now cycles through the demos
without obvious issue under the same conditions that caused the light
map update code to segfault.
This commit is contained in:
Bill Currie 2021-01-23 12:01:52 +09:00
parent 328a529a94
commit c989c8a6b6
7 changed files with 159 additions and 349 deletions

View file

@ -1,6 +1,8 @@
#ifndef __QF_Vulkan_staging_h
#define __QF_Vulkan_staging_h
#include "QF/ringbuffer.h"
typedef struct qfv_packet_s {
struct qfv_stagebuf_s *stage; ///< staging buffer that owns this packet
VkCommandBuffer cmd;
@ -13,21 +15,18 @@ typedef struct qfv_stagebuf_s {
struct qfv_device_s *device;
VkBuffer buffer;
VkDeviceMemory memory;
qfv_packet_t *packet; ///< array of packets for controlling access
size_t num_packets;///< number of packets in array
size_t next_packet;///< index of the next packet to be used
size_t size; ///< actual size of the buffer
RING_BUFFER(qfv_packet_t, 4) packets; ///< packets for controlling access
size_t atom_mask; ///< for flush size rounding
size_t size; ///< actual size of the buffer
size_t end; ///< effective end of the buffer due to early wrap
size_t head;
size_t tail;
size_t space_start;///< beginning of available space
size_t space_end; ///< end of available space
void *data;
} qfv_stagebuf_t;
qfv_stagebuf_t *QFV_CreateStagingBuffer (struct qfv_device_s *device,
size_t size, int num_packets,
VkCommandPool cmdPool);
size_t size, VkCommandPool cmdPool);
void QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage);
void QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size);
qfv_packet_t *QFV_PacketAcquire (qfv_stagebuf_t *stage);

View file

@ -211,7 +211,7 @@ load_textures (model_t *model, vulkan_ctx_t *ctx)
memsize, 0);
mctx->texture_memory = mem;
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, memsize, 1,
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (device, memsize,
ctx->cmdpool);
qfv_packet_t *packet = QFV_PacketAcquire (stage);
buffer = QFV_PacketExtend (packet, memsize);

View file

@ -55,14 +55,13 @@
#include "vid_vulkan.h"
qfv_stagebuf_t *
QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, int num_packets,
QFV_CreateStagingBuffer (qfv_device_t *device, size_t size,
VkCommandPool cmdPool)
{
size_t atom = device->physDev->properties.limits.nonCoherentAtomSize;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_stagebuf_t *stage = malloc (sizeof (qfv_stagebuf_t)
+ num_packets * sizeof (qfv_packet_t));
qfv_stagebuf_t *stage = calloc (1, sizeof (qfv_stagebuf_t));
stage->atom_mask = atom - 1;
size = (size + stage->atom_mask) & ~stage->atom_mask;
stage->device = device;
@ -71,25 +70,23 @@ QFV_CreateStagingBuffer (qfv_device_t *device, size_t size, int num_packets,
stage->memory = QFV_AllocBufferMemory (device, stage->buffer,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
size, 0);
stage->packet = (qfv_packet_t *) (stage + 1);
stage->num_packets = num_packets;
stage->next_packet = 0;
stage->size = size;
stage->end = size;
stage->head = 0;
stage->tail = 0;
dfunc->vkMapMemory (device->dev, stage->memory, 0, size, 0, &stage->data);
QFV_BindBufferMemory (device, stage->buffer, stage->memory, 0);
__auto_type bufferset = QFV_AllocCommandBufferSet (num_packets, alloca);
int count = RB_buffer_size (&stage->packets);
__auto_type bufferset = QFV_AllocCommandBufferSet (count, alloca);
QFV_AllocateCommandBuffers (device, cmdPool, 0, bufferset);
for (int i = 0; i < num_packets; i++) {
stage->packet[i].stage = stage;
stage->packet[i].cmd = bufferset->a[i];
stage->packet[i].fence = QFV_CreateFence (device, 1);
stage->packet[i].offset = 0;
stage->packet[i].length = 0;
for (int i = 0; i < count; i++) {
qfv_packet_t *packet = &stage->packets.buffer[i];
packet->stage = stage;
packet->cmd = bufferset->a[i];
packet->fence = QFV_CreateFence (device, 1);
packet->offset = 0;
packet->length = 0;
}
return stage;
}
@ -100,14 +97,15 @@ QFV_DestroyStagingBuffer (qfv_stagebuf_t *stage)
qfv_device_t *device = stage->device;
qfv_devfuncs_t *dfunc = device->funcs;
__auto_type fences = QFV_AllocFenceSet (stage->num_packets, alloca);
for (size_t i = 0; i < stage->num_packets; i++) {
fences->a[i] = stage->packet[i].fence;
int count = RB_buffer_size (&stage->packets);
__auto_type fences = QFV_AllocFenceSet (count, alloca);
for (int i = 0; i < count; i++) {
fences->a[i] = stage->packets.buffer[i].fence;
}
dfunc->vkWaitForFences (device->dev, fences->size, fences->a, VK_TRUE,
~0ull);
for (size_t i = 0; i < stage->num_packets; i++) {
dfunc->vkDestroyFence (device->dev, stage->packet[i].fence, 0);
500000000ull);
for (int i = 0; i < count; i++) {
dfunc->vkDestroyFence (device->dev, fences->a[i], 0);
}
dfunc->vkUnmapMemory (device->dev, stage->memory);
@ -132,44 +130,87 @@ QFV_FlushStagingBuffer (qfv_stagebuf_t *stage, size_t offset, size_t size)
}
static void
advance_tail (qfv_stagebuf_t *stage, qfv_packet_t *packet)
release_space (qfv_stagebuf_t *stage, size_t offset, size_t length)
{
if (stage->space_end != offset
&& offset != 0
&& stage->space_end != stage->end) {
Sys_Error ("staging: out of sequence packet release");
}
if (stage->space_end == stage->end) {
stage->space_end = 0;
stage->end = stage->size;
}
stage->space_end += length;
}
static void *
acquire_space (qfv_packet_t *packet, size_t size)
{
qfv_stagebuf_t *stage = packet->stage;
qfv_device_t *device = stage->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_packet_t *start = packet;
while (1) {
if ((size_t) (++packet - stage->packet) >= stage->num_packets) {
packet = stage->packet;
// clean up after any completed packets
while (RB_DATA_AVAILABLE (stage->packets) > 1) {
qfv_packet_t *p = RB_PEEK_DATA (stage->packets, 0);
if (dfunc->vkGetFenceStatus (device->dev, p->fence) != VK_SUCCESS) {
break;
}
if (packet != start
&& (dfunc->vkGetFenceStatus (device->dev, packet->fence)
== VK_SUCCESS)) {
if (packet->length == 0) {
continue;
}
if ((stage->tail == stage->end && packet->offset == 0)
|| stage->tail == packet->offset) {
stage->tail = packet->offset + packet->length;
packet->length = 0;
if (stage->tail >= stage->end) {
stage->end = stage->size;
stage->tail = stage->size;
}
}
continue;
}
// Packets are always aquired in sequence and thus the first busy
// packet after the start packet marks the end of available space.
// Alternatively, there is only one packet and we've looped around
// back to the start packet. Must ensure the tail is updated
if (stage->tail >= stage->end && packet->offset == 0) {
stage->end = stage->size;
stage->tail = packet->offset;
}
break;
release_space (stage, p->offset, p->length);
RB_RELEASE (stage->packets, 1);
}
if (size > stage->size) {
// utterly impossible allocation
return 0;
}
// if the staging buffer has been freed up and no data is assigned to the
// single existing packet, then ensure the packet starts at the beginning
// of the staging buffer in order to maximize the space available to it
// (some of the tests are redundant since if any space is assigned to a
// packet, the buffer cannot be fully freed up)
if (stage->space_end == stage->space_start
&& RB_DATA_AVAILABLE (stage->packets) == 1
&& packet->length == 0) {
stage->space_end = 0;
stage->space_start = 0;
packet->offset = 0;
}
if (stage->space_start >= stage->space_end) {
// all the space to the actual end of the buffer is free
if (stage->space_start + size <= stage->size) {
void *data = (byte *) stage->data + stage->space_start;
stage->space_start += size;
return data;
}
// doesn't fit at the end of the buffer, try the beginning but only
// if the packet can be moved (no spaced has been allocated to it yet)
if (packet->length > 0) {
// can't move it
return 0;
}
// mark the unused end of the buffer such that it gets reclaimed
// properly when the preceeding packet is freed
stage->end = stage->space_start;
stage->space_start = 0;
packet->offset = 0;
}
while (stage->space_start + size > stage->space_end
&& RB_DATA_AVAILABLE (stage->packets) > 1) {
packet = RB_PEEK_DATA (stage->packets, 0);
dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE,
~0ull);
release_space (stage, packet->offset, packet->length);
RB_RELEASE (stage->packets, 1);
}
if (stage->space_start + size > stage->space_end) {
return 0;
}
void *data = (byte *) stage->data + stage->space_start;
stage->space_start += size;
return data;
}
qfv_packet_t *
@ -177,16 +218,19 @@ QFV_PacketAcquire (qfv_stagebuf_t *stage)
{
qfv_device_t *device = stage->device;
qfv_devfuncs_t *dfunc = device->funcs;
qfv_packet_t *packet = &stage->packet[stage->next_packet++];
stage->next_packet %= stage->num_packets;
dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE, ~0ull);
advance_tail (stage, packet);
if (stage->head == stage->size) {
stage->head = 0;
qfv_packet_t *packet = 0;
if (!RB_SPACE_AVAILABLE (stage->packets)) {
// need to wait for a packet to become available
packet = RB_PEEK_DATA (stage->packets, 0);
dfunc->vkWaitForFences (device->dev, 1, &packet->fence, VK_TRUE,
~0ull);
release_space (stage, packet->offset, packet->length);
RB_RELEASE (stage->packets, 1);
}
packet->offset = stage->head;
packet = RB_ACQUIRE (stage->packets, 1);
packet->offset = stage->space_start;
packet->length = 0;
dfunc->vkResetFences (device->dev, 1, &packet->fence);
@ -203,40 +247,10 @@ QFV_PacketAcquire (qfv_stagebuf_t *stage)
void *
QFV_PacketExtend (qfv_packet_t *packet, size_t size)
{
qfv_stagebuf_t *stage = packet->stage;
if (!size || size > stage->size) {
return 0;
void *data = acquire_space (packet, size);
if (data) {
packet->length += size;
}
//FIXME extra logic may be needed to wait wait for space to become
//available when the requested size should fit but can't due to in-flight
//packets
advance_tail (stage, packet);
size_t head = stage->head;
size_t end = stage->end;
if (head + size > stage->end) {
if (packet->length) {
// packets cannot wrap around the buffer (must use separate
// packets)
return 0;
}
if (stage->tail == 0) {
// the beginning of the the staging buffer is occupied
return 0;
}
packet->offset = 0;
head = 0;
end = stage->head;
}
if (head < stage->tail && head + size > stage->tail) {
// not enough room for the sub-packet
return 0;
}
void *data = (byte *) stage->data + head;
stage->end = end;
stage->head = head + size;
packet->length += size;
return data;
}

View file

@ -66,12 +66,17 @@ vkCreateFence (VkDevice device, const VkFenceCreateInfo *info,
return VK_SUCCESS;
}
int wait_count = 0;
static VkResult
vkWaitForFences (VkDevice device, uint32_t fenceCount, const VkFence *fences,
VkBool32 waitAll, uint64_t timeout)
{
for (uint32_t i = 0; i < fenceCount; i++) {
int *f = (int *)fences[i];
if (*f) {
wait_count++;
}
*f = 0;
}
return VK_SUCCESS;
@ -145,7 +150,13 @@ qfv_devfuncs_t dfuncs = {
vkFlushMappedMemoryRanges:vkFlushMappedMemoryRanges,
vkQueueSubmit:vkQueueSubmit,
};
qfv_physdev_t physDev;
qfv_physdev_t physDev = {
properties:{
limits:{
nonCoherentAtomSize:256,
},
},
};
qfv_device_t device = {
physDev:&physDev,
funcs:&dfuncs,
@ -168,271 +179,59 @@ _error (int line, const char *fmt, ...)
int
main (void)
{
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, 1024, 4, 0);
qfv_stagebuf_t *stage = QFV_CreateStagingBuffer (&device, 1024, 0);
if (stage->num_packets != 4) {
error ("stage has incorrect packet count: %zd\n", stage->num_packets);
}
if (stage->next_packet != 0) {
error ("stage has incorrect next_packet: %zd\n", stage->next_packet);
}
if (stage->size != 1024) {
error ("stage has incorrect size: %zd\n", stage->size);
error ("stage has incorrect size: %zd", stage->size);
}
if (stage->end != stage->size) {
error ("stage has incorrect end: %zd\n", stage->end);
}
if (stage->head || stage->tail != stage->head) {
error ("stage ring buffer not initialized: h:%zd t:%zd\n",
stage->head, stage->tail);
error ("stage has incorrect end: %zd", stage->end);
}
if (!stage->data || stage->data != stage_memory) {
error ("stage memory not mapped: d:%p, m:%p\n",
error ("stage memory not mapped: d:%p, m:%p",
stage->data, stage_memory);
}
for (size_t i = 0; i < stage->num_packets; i++) {
qfv_packet_t *p = &stage->packet[i];
for (size_t i = 0; i < RB_buffer_size (&stage->packets); i++) {
qfv_packet_t *p = &stage->packets.buffer[i];
if (p->stage != stage) {
error ("packet[%zd] stage not set: ps:%p s:%p\n", i,
error ("packet[%zd] stage not set: ps:%p s:%p", i,
p->stage, stage);
}
if (!p->cmd) {
error ("packet[%zd] has no command buffer\n", i);
error ("packet[%zd] has no command buffer", i);
}
if (!p->fence) {
error ("packet[%zd] has no fence\n", i);
}
for (size_t j = 0; j < i; j++) {
qfv_packet_t *q = &stage->packet[j];
if (q->cmd == p->cmd || q->fence == p->fence) {
error ("packet[%zd] has dup fence or cmd buf\n", i);
}
error ("packet[%zd] has no fence", i);
}
if (vkGetFenceStatus (device.dev, p->fence) != VK_SUCCESS) {
error ("packet[%zd].fence is not signaled\n", i);
error ("packet[%zd].fence is not signaled", i);
}
if (p->offset || p->length) {
error ("packet[%zd] size/length not initialized: o:%zd l:%zd\n",
error ("packet[%zd] size/length not initialized: o:%zd l:%zd",
i, p->offset, p->length);
}
}
qfv_packet_t *packet = QFV_PacketAcquire (stage);
if (!packet) {
error ("could not get a packet");
}
if (RB_DATA_AVAILABLE (stage->packets) != 1) {
error ("in flight packet count incorrect");
}
if (vkGetFenceStatus (device.dev, packet->fence) != VK_NOT_READY) {
error ("packet.fence is signaled\n");
error ("packet.fence is signaled");
}
if (QFV_PacketExtend (packet, 2048)) {
error ("2048 byte request did not return null");
}
if (!QFV_PacketExtend (packet, 1024)) {
error ("1024 byte request returned null");
}
if (QFV_PacketExtend (packet, 1)) {
error ("1 byte request did not return null");
}
void *data;
size_t old_head, old_tail;
old_head = stage->head;
old_tail = stage->tail;
data = QFV_PacketExtend (packet, 0);
if (data) {
error ("0 byte extend did not return null\n");
}
if (stage->head != old_head || stage->tail != old_tail) {
error ("0 byte extend moved head or tail\n");
}
data = QFV_PacketExtend (packet, 2048);
if (data) {
error ("2048 byte extend did not return null\n");
}
if (stage->head != old_head || stage->tail != old_tail) {
error ("2048 byte extend moved head or tail\n");
}
data = QFV_PacketExtend (packet, 1024);
if (!data) {
error ("1024 byte extend failed\n");
}
if (stage->head == old_head) {
error ("1024 byte extend did not move head\n");
}
if (stage->tail != old_tail) {
error ("1024 byte extend moved tail\n");
}
if (stage->head > stage->size) {
error ("stage head out of bounds: %zd\n", stage->head);
}
if (packet->offset != old_head || packet->length != 1024) {
error ("packet offset/size incorrect: p:%zd,%zd h:%zd\n",
packet->offset, packet->length, old_head);
}
if (stage->head < packet->offset + packet->length) {
error ("stage head before end of packet: %zd, pe:%zd\n",
stage->head, packet->offset + packet->length);
}
old_head = stage->head;
old_tail = stage->tail;
data = QFV_PacketExtend (packet, 16);
if (data) {
error ("16 byte extend in full stage did not return null\n");
}
if (stage->head != old_head || stage->tail != old_tail) {
error ("16 byte extend moved head or tail\n");
}
QFV_PacketSubmit (packet);
if (vkGetFenceStatus (device.dev, packet->fence) != VK_SUCCESS) {
error ("packet.fence is not signaled\n");
}
if (stage->head != 1024 || stage->tail != 0) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
qfv_packet_t *packet2 = QFV_PacketAcquire (stage);
if (!packet2 || packet2 == packet) {
error ("did not get new packet: n:%p o:%p\n", packet2, packet);
}
packet = packet2;
if (packet->offset != 0 || stage->head != 0 || stage->tail != 0) {
error ("new packet did not wrap: p:%zd h:%zd t:%zd\n",
packet2->offset, stage->head, stage->tail);
}
old_head = stage->head;
old_tail = stage->tail;
data = QFV_PacketExtend (packet, 768);
if (!data) {
error ("768 byte extend failed\n");
}
if (stage->head == old_head) {
error ("768 byte extend did not move head\n");
}
if (stage->tail != 0) {
error ("768 byte extend dit not wrap tail: %zd\n", stage->tail);
}
if (stage->head > stage->size) {
error ("stage head out of bounds: %zd\n", stage->head);
}
if (packet->offset != old_head || packet->length != 768) {
error ("packet offset/size incorrect: p:%zd,%zd h:%zd\n",
packet->offset, packet->length, old_head);
}
if (stage->head < packet->offset + packet->length) {
error ("stage head before end of packet: %zd, pe:%zd\n",
stage->head, packet->offset + packet->length);
}
// test attempting to wrap the packet (without needed space)
old_head = stage->head;
old_tail = stage->tail;
data = QFV_PacketExtend (packet, 512);
if (data) {
error ("512 byte extend in partially full stage succeeded\n");
}
if (stage->head != old_head || stage->tail != old_tail) {
error ("512 byte extend moved head or tail\n");
}
QFV_PacketSubmit (packet);
if (stage->head != 768 || stage->tail != 0) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
packet = QFV_PacketAcquire (stage);
// test wrapping a new packet
data = QFV_PacketExtend (packet, 512);
if (!data) {
error ("512 byte extend failed\n");
}
if (packet->offset != 0 || packet->length != 512) {
error ("packet offset/size incorrect: p:%zd,%zd\n",
packet->offset, packet->length);
}
if (stage->head != 512 || stage->tail != stage->end || stage->end !=768) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
data = QFV_PacketExtend (packet, 512);
if (!data) {
error ("second 512 byte extend failed\n");
}
if (packet->offset != 0 || packet->length != 1024) {
error ("packet offset/size incorrect: p:%zd,%zd\n",
packet->offset, packet->length);
}
if (stage->head != 1024 || stage->tail != 0 || stage->end != 1024) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
QFV_PacketSubmit (packet);
packet = QFV_PacketAcquire (stage);
data = QFV_PacketExtend (packet, 512);
if (!data) {
error ("512 byte extend failed\n");
}
if (packet->offset != 0 || packet->length != 512) {
error ("packet offset/size incorrect: p:%zd,%zd\n",
packet->offset, packet->length);
}
QFV_PacketSubmit (packet);
if (stage->head != 512 || stage->tail != 0 || stage->end != 1024) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
packet = QFV_PacketAcquire (stage);
data = QFV_PacketExtend (packet, 256);
if (!data) {
error ("256 byte extend failed\n");
}
if (packet->offset != 512 || packet->length != 256) {
error ("packet offset/size incorrect: p:%zd,%zd\n",
packet->offset, packet->length);
}
if (stage->head != 768 || stage->tail != 512 || stage->end != 1024) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
// don't submit yet. Normally, it would be an error, but the test harness
// needs to keep the packet on hand for the following tests to work
packet2 = QFV_PacketAcquire (stage);
old_head = stage->head;
old_tail = stage->tail;
data = QFV_PacketExtend (packet2, 768);
if (data) {
error ("768 byte extend did not return null\n");
}
if (stage->head != old_head || stage->tail != old_tail) {
error ("768 byte extend moved head or tail\n");
}
//should wrap
data = QFV_PacketExtend (packet2, 512);
if (!data) {
error ("512 byte extend failed\n");
}
if (packet2->offset != 0 || packet2->length != 512) {
error ("packet offset/size incorrect: p:%zd,%zd\n",
packet2->offset, packet2->length);
}
if (stage->head != 512 || stage->tail != 512 || stage->end != 768) {
error ("stage head or tail not as expected: h: %zd t:%zd\n",
stage->head, stage->tail);
}
//submit the first packet
QFV_PacketSubmit (packet);
packet = QFV_PacketAcquire (stage);
old_head = stage->head;
old_tail = stage->tail;
data = QFV_PacketExtend (packet, 768);
if (data) {
error ("768 byte extend did not return null\n");
}
if (stage->head != old_head || stage->tail != old_tail) {
error ("768 byte extend moved head or tail\n");
}
return 0;
}

View file

@ -465,8 +465,7 @@ Vulkan_BuildDisplayLists (model_t **models, int num_models, vulkan_ctx_t *ctx)
size_t vertex_buffer_size = vertex_count * sizeof (bspvert_t);
index_buffer_size = (index_buffer_size + atom_mask) & ~atom_mask;
stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, 1,
ctx->cmdpool);
stage = QFV_CreateStagingBuffer (device, vertex_buffer_size, ctx->cmdpool);
qfv_packet_t *packet = QFV_PacketAcquire (stage);
vertices = QFV_PacketExtend (packet, vertex_buffer_size);
vertex_index_base = 0;
@ -1289,8 +1288,7 @@ Vulkan_Bsp_Init (vulkan_ctx_t *ctx)
bctx->light_scrap = QFV_CreateScrap (device, 2048, tex_frgba, ctx->staging);
size_t size = QFV_ScrapSize (bctx->light_scrap);
bctx->light_stage = QFV_CreateStagingBuffer (device, size, 3,
ctx->cmdpool);
bctx->light_stage = QFV_CreateStagingBuffer (device, size, ctx->cmdpool);
DARRAY_INIT (&bctx->texture_chains, 64);

View file

@ -367,7 +367,7 @@ Vulkan_Draw_Init (vulkan_ctx_t *ctx)
0, 0);
create_quad_buffers (ctx);
dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024, 4,
dctx->stage = QFV_CreateStagingBuffer (device, 4 * 1024 * 1024,
ctx->cmdpool);
dctx->scrap = QFV_CreateScrap (device, 2048, tex_rgba, dctx->stage);
dctx->sampler = QFV_GetSampler (ctx, "quakepic");

View file

@ -204,7 +204,7 @@ Vulkan_CreateDevice (vulkan_ctx_t *ctx)
void
Vulkan_CreateStagingBuffers (vulkan_ctx_t *ctx)
{
ctx->staging = QFV_CreateStagingBuffer (ctx->device, 4*1024*1024, 1,
ctx->staging = QFV_CreateStagingBuffer (ctx->device, 4*1024*1024,
ctx->cmdpool);
}