mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-16 06:00:33 +01:00
vk: draft staging api, use it for textures
This commit is contained in:
parent
573d006c4a
commit
a3ff75b48f
@ -1,22 +1,5 @@
|
||||
#include "vk_buffer.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
vk_global_buffer_t g_vk_buffers = {0};
|
||||
|
||||
#define DEFAULT_STAGING_SIZE (16*1024*1024)
|
||||
|
||||
qboolean VK_BuffersInit( void ) {
|
||||
if (!VK_BufferCreate("staging", &g_vk_buffers.staging, DEFAULT_STAGING_SIZE, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VK_BuffersDestroy( void ) {
|
||||
VK_BufferDestroy(&g_vk_buffers.staging);
|
||||
}
|
||||
|
||||
qboolean VK_BufferCreate(const char *debug_name, vk_buffer_t *buf, uint32_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags flags)
|
||||
{
|
||||
VkBufferCreateInfo bci = {
|
||||
@ -50,7 +33,6 @@ void VK_BufferDestroy(vk_buffer_t *buf) {
|
||||
buf->buffer = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
// FIXME when there are many allocation per VkDeviceMemory, fix this
|
||||
if (buf->devmem.device_memory) {
|
||||
VK_DevMemFree(&buf->devmem);
|
||||
buf->devmem.device_memory = VK_NULL_HANDLE;
|
||||
|
@ -11,15 +11,6 @@ typedef struct vk_buffer_s {
|
||||
uint32_t size;
|
||||
} vk_buffer_t;
|
||||
|
||||
typedef struct {
|
||||
vk_buffer_t staging;
|
||||
} vk_global_buffer_t;
|
||||
|
||||
extern vk_global_buffer_t g_vk_buffers;
|
||||
|
||||
qboolean VK_BuffersInit( void );
|
||||
void VK_BuffersDestroy( void );
|
||||
|
||||
qboolean VK_BufferCreate(const char *debug_name, vk_buffer_t *buf, uint32_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags flags);
|
||||
void VK_BufferDestroy(vk_buffer_t *buf);
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include "vk_textures.h"
|
||||
#include "vk_2d.h"
|
||||
#include "vk_renderstate.h"
|
||||
#include "vk_buffer.h"
|
||||
#include "vk_staging.h"
|
||||
#include "vk_framectl.h"
|
||||
#include "vk_brush.h"
|
||||
#include "vk_scene.h"
|
||||
@ -703,7 +703,7 @@ qboolean R_VkInit( void )
|
||||
if (!VK_DevMemInit())
|
||||
return false;
|
||||
|
||||
if (!VK_BuffersInit())
|
||||
if (!R_VkStagingInit())
|
||||
return false;
|
||||
|
||||
// TODO move this to vk_texture module
|
||||
@ -789,7 +789,7 @@ void R_VkShutdown( void ) {
|
||||
VK_DescriptorShutdown();
|
||||
|
||||
vkDestroySampler(vk_core.device, vk_core.default_sampler, NULL);
|
||||
VK_BuffersDestroy();
|
||||
R_VkStagingShutdown();
|
||||
|
||||
VK_DevMemDestroy();
|
||||
|
||||
|
143
ref_vk/vk_staging.c
Normal file
143
ref_vk/vk_staging.c
Normal file
@ -0,0 +1,143 @@
|
||||
#include "vk_staging.h"
|
||||
#include "vk_buffer.h"
|
||||
|
||||
#include <memory.h>
|
||||
|
||||
#define DEFAULT_STAGING_SIZE (16*1024*1024)
|
||||
#define MAX_STAGING_ALLOCS (1024)
|
||||
|
||||
typedef struct {
|
||||
int offset, size;
|
||||
enum { DestNone, DestBuffer, DestImage } dest_type;
|
||||
union {
|
||||
struct {
|
||||
VkBuffer buffer;
|
||||
VkDeviceSize offset;
|
||||
} buffer;
|
||||
struct {
|
||||
VkImage image;
|
||||
VkImageLayout layout;
|
||||
VkBufferImageCopy region;
|
||||
} image;
|
||||
};
|
||||
} staging_alloc_t;
|
||||
|
||||
static struct {
|
||||
vk_buffer_t buffer;
|
||||
staging_alloc_t allocs[MAX_STAGING_ALLOCS];
|
||||
int num_allocs;
|
||||
} g_staging = {0};
|
||||
|
||||
qboolean R_VkStagingInit(void) {
|
||||
if (!VK_BufferCreate("staging", &g_staging.buffer, DEFAULT_STAGING_SIZE, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void R_VkStagingShutdown(void) {
|
||||
VK_BufferDestroy(&g_staging.buffer);
|
||||
}
|
||||
|
||||
vk_staging_region_t R_VkStagingLock(size_t size) {
|
||||
const int offset = g_staging.num_allocs > 0 ? g_staging.allocs[g_staging.num_allocs - 1].offset + g_staging.allocs[g_staging.num_allocs - 1].size : 0;
|
||||
|
||||
if ( g_staging.num_allocs >= MAX_STAGING_ALLOCS )
|
||||
return (vk_staging_region_t){0};
|
||||
|
||||
if ( offset + size > g_staging.buffer.size )
|
||||
return (vk_staging_region_t){0};
|
||||
|
||||
memset(g_staging.allocs + g_staging.num_allocs, 0, sizeof(staging_alloc_t));
|
||||
g_staging.allocs[g_staging.num_allocs].offset = offset;
|
||||
g_staging.allocs[g_staging.num_allocs].size = size;
|
||||
g_staging.num_allocs++;
|
||||
return (vk_staging_region_t){(char*)g_staging.buffer.mapped + offset, size, g_staging.num_allocs - 1};
|
||||
}
|
||||
|
||||
/*
|
||||
void R_VkStagingUnlockToBuffer(const vk_staging_region_t* region, VkBuffer dest, size_t dest_offset) {
|
||||
ASSERT(region->internal_id_ >= 0 && region->internal_id_ < g_staging.num_allocs);
|
||||
ASSERT(g_staging.allocs[region->internal_id_].dest == VK_NULL_HANDLE);
|
||||
|
||||
g_staging.allocs[region->internal_id_].dest = dest;
|
||||
g_staging.allocs[region->internal_id_].dest_offset = dest_offset;
|
||||
}
|
||||
*/
|
||||
|
||||
void R_VkStagingUnlockToImage(const vk_staging_region_t* region, VkBufferImageCopy* dest_region, VkImageLayout layout, VkImage dest) {
|
||||
staging_alloc_t *alloc;
|
||||
ASSERT(region->internal_id_ >= 0 && region->internal_id_ < g_staging.num_allocs);
|
||||
ASSERT(g_staging.allocs[region->internal_id_].dest_type == DestNone);
|
||||
|
||||
alloc = g_staging.allocs + region->internal_id_;
|
||||
alloc->dest_type = DestImage;
|
||||
alloc->image.layout = layout;
|
||||
alloc->image.image = dest;
|
||||
alloc->image.region = *dest_region;
|
||||
alloc->image.region.bufferOffset += alloc->offset;
|
||||
}
|
||||
|
||||
static void copyImage(VkCommandBuffer cmdbuf, const staging_alloc_t *alloc) {
|
||||
vkCmdCopyBufferToImage(cmdbuf, g_staging.buffer.buffer, alloc->image.image, alloc->image.layout, 1, &alloc->image.region);
|
||||
}
|
||||
|
||||
void R_VkStagingCommit(VkCommandBuffer cmdbuf) {
|
||||
for ( int i = 0; i < g_staging.num_allocs; i++ ) {
|
||||
staging_alloc_t *const alloc = g_staging.allocs + i;
|
||||
ASSERT(alloc->dest_type != DestNone);
|
||||
switch (alloc->dest_type) {
|
||||
case DestImage:
|
||||
copyImage(cmdbuf, alloc);
|
||||
break;
|
||||
case DestBuffer:
|
||||
ASSERT(!"staging dest buffer is not implemented");
|
||||
break;
|
||||
}
|
||||
|
||||
alloc->dest_type = DestNone;
|
||||
|
||||
#if 0
|
||||
// TODO coalesce staging regions for the same dest buffer
|
||||
|
||||
const VkBufferCopy copy = {
|
||||
.srcOffset = g_staging.allocs[i].offset,
|
||||
.dstOffset = g_staging.allocs[i].dest_offset,
|
||||
.size = g_staging.allocs[i].size
|
||||
};
|
||||
vkCmdCopyBuffer(cmdbuf, g_staging.buffer.buffer, g_staging.allocs[i].dest, 1, ©);
|
||||
|
||||
// TODO decide whether this needs to do anything with barriers
|
||||
// here we can only collect dirty regions for each dest buffer
|
||||
#endif
|
||||
}
|
||||
|
||||
g_staging.num_allocs = 0;
|
||||
}
|
||||
|
||||
void R_VkStagingFlushSync(void) {
|
||||
if ( !g_staging.num_allocs )
|
||||
return;
|
||||
|
||||
{
|
||||
// FIXME get the right one
|
||||
const VkCommandBuffer cmdbuf = vk_core.upload_pool.buffers[0];
|
||||
|
||||
const VkCommandBufferBeginInfo beginfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
|
||||
};
|
||||
|
||||
const VkSubmitInfo subinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &cmdbuf,
|
||||
};
|
||||
|
||||
XVK_CHECK(vkBeginCommandBuffer(cmdbuf, &beginfo));
|
||||
R_VkStagingCommit(cmdbuf);
|
||||
XVK_CHECK(vkEndCommandBuffer(cmdbuf));
|
||||
XVK_CHECK(vkQueueSubmit(vk_core.queue, 1, &subinfo, VK_NULL_HANDLE));
|
||||
XVK_CHECK(vkQueueWaitIdle(vk_core.queue));
|
||||
}
|
||||
}
|
27
ref_vk/vk_staging.h
Normal file
27
ref_vk/vk_staging.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "vk_core.h"
|
||||
|
||||
qboolean R_VkStagingInit(void);
|
||||
void R_VkStagingShutdown(void);
|
||||
|
||||
//void *R_VkStagingAlloc(size_t size, VkBuffer dest, size_t dest_offset);
|
||||
|
||||
typedef struct {
|
||||
void *ptr;
|
||||
size_t size;
|
||||
int internal_id_;
|
||||
} vk_staging_region_t;
|
||||
vk_staging_region_t R_VkStagingLock(size_t size);
|
||||
void R_VkStagingUnlockToBuffer(const vk_staging_region_t* region, VkBuffer dest, size_t dest_offset);
|
||||
void R_VkStagingUnlockToImage(const vk_staging_region_t* region, VkBufferImageCopy* dest_region, VkImageLayout layout, VkImage dest);
|
||||
|
||||
void R_VkStagingCommit(VkCommandBuffer cmdbuf);
|
||||
|
||||
// Force commit synchronously
|
||||
void R_VkStagingFlushSync(void);
|
||||
|
||||
// TODO
|
||||
// - [x] call init/shutdown from vk_core.ckkjkj
|
||||
// - [x] use this in vk_texture.c
|
||||
// - [ ] use this in vk_render.c
|
@ -2,7 +2,7 @@
|
||||
|
||||
#include "vk_common.h"
|
||||
#include "vk_core.h"
|
||||
#include "vk_buffer.h"
|
||||
#include "vk_staging.h"
|
||||
#include "vk_const.h"
|
||||
#include "vk_descriptor.h"
|
||||
#include "vk_mapents.h" // wadlist
|
||||
@ -546,8 +546,6 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||
}
|
||||
|
||||
{
|
||||
size_t staging_offset = 0; // TODO multiple staging buffer users params.staging->ptr
|
||||
|
||||
// 5. Create/get cmdbuf for transitions
|
||||
VkCommandBufferBeginInfo beginfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
@ -587,7 +585,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||
const size_t mip_size = CalcImageSize( pic->type, width, height, 1 );
|
||||
|
||||
VkBufferImageCopy region = {0};
|
||||
region.bufferOffset = staging_offset;
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource = (VkImageSubresourceLayers){
|
||||
@ -602,20 +600,22 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||
.depth = 1,
|
||||
};
|
||||
|
||||
memcpy(((uint8_t*)g_vk_buffers.staging.mapped) + staging_offset, buf, mip_size);
|
||||
vk_staging_region_t staging = R_VkStagingLock(mip_size);
|
||||
ASSERT(staging.ptr);
|
||||
memcpy(staging.ptr, buf, mip_size);
|
||||
|
||||
// Build mip in place for the next mip level
|
||||
if ( mip < mipCount - 1 )
|
||||
{
|
||||
BuildMipMap( buf, width, height, 1, tex->flags );
|
||||
}
|
||||
|
||||
// TODO we could do this only once w/ region array
|
||||
vkCmdCopyBufferToImage(cmdbuf, g_vk_buffers.staging.buffer, tex->vk.image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
staging_offset += mip_size;
|
||||
R_VkStagingUnlockToImage(&staging, ®ion, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, tex->vk.image.image);
|
||||
}
|
||||
}
|
||||
|
||||
R_VkStagingCommit(cmdbuf);
|
||||
|
||||
// 5.2 image:layout:DST -> image:layout:SAMPLED
|
||||
// 5.2.1 transitionToLayout(DST -> SHADER_READ_ONLY)
|
||||
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
Loading…
Reference in New Issue
Block a user