mirror of
https://github.com/w23/xash3d-fwgs
synced 2025-01-18 14:50:05 +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 "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)
|
qboolean VK_BufferCreate(const char *debug_name, vk_buffer_t *buf, uint32_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags flags)
|
||||||
{
|
{
|
||||||
VkBufferCreateInfo bci = {
|
VkBufferCreateInfo bci = {
|
||||||
@ -50,7 +33,6 @@ void VK_BufferDestroy(vk_buffer_t *buf) {
|
|||||||
buf->buffer = VK_NULL_HANDLE;
|
buf->buffer = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME when there are many allocation per VkDeviceMemory, fix this
|
|
||||||
if (buf->devmem.device_memory) {
|
if (buf->devmem.device_memory) {
|
||||||
VK_DevMemFree(&buf->devmem);
|
VK_DevMemFree(&buf->devmem);
|
||||||
buf->devmem.device_memory = VK_NULL_HANDLE;
|
buf->devmem.device_memory = VK_NULL_HANDLE;
|
||||||
|
@ -11,15 +11,6 @@ typedef struct vk_buffer_s {
|
|||||||
uint32_t size;
|
uint32_t size;
|
||||||
} vk_buffer_t;
|
} 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);
|
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);
|
void VK_BufferDestroy(vk_buffer_t *buf);
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include "vk_textures.h"
|
#include "vk_textures.h"
|
||||||
#include "vk_2d.h"
|
#include "vk_2d.h"
|
||||||
#include "vk_renderstate.h"
|
#include "vk_renderstate.h"
|
||||||
#include "vk_buffer.h"
|
#include "vk_staging.h"
|
||||||
#include "vk_framectl.h"
|
#include "vk_framectl.h"
|
||||||
#include "vk_brush.h"
|
#include "vk_brush.h"
|
||||||
#include "vk_scene.h"
|
#include "vk_scene.h"
|
||||||
@ -703,7 +703,7 @@ qboolean R_VkInit( void )
|
|||||||
if (!VK_DevMemInit())
|
if (!VK_DevMemInit())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!VK_BuffersInit())
|
if (!R_VkStagingInit())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO move this to vk_texture module
|
// TODO move this to vk_texture module
|
||||||
@ -789,7 +789,7 @@ void R_VkShutdown( void ) {
|
|||||||
VK_DescriptorShutdown();
|
VK_DescriptorShutdown();
|
||||||
|
|
||||||
vkDestroySampler(vk_core.device, vk_core.default_sampler, NULL);
|
vkDestroySampler(vk_core.device, vk_core.default_sampler, NULL);
|
||||||
VK_BuffersDestroy();
|
R_VkStagingShutdown();
|
||||||
|
|
||||||
VK_DevMemDestroy();
|
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_common.h"
|
||||||
#include "vk_core.h"
|
#include "vk_core.h"
|
||||||
#include "vk_buffer.h"
|
#include "vk_staging.h"
|
||||||
#include "vk_const.h"
|
#include "vk_const.h"
|
||||||
#include "vk_descriptor.h"
|
#include "vk_descriptor.h"
|
||||||
#include "vk_mapents.h" // wadlist
|
#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
|
// 5. Create/get cmdbuf for transitions
|
||||||
VkCommandBufferBeginInfo beginfo = {
|
VkCommandBufferBeginInfo beginfo = {
|
||||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
.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 );
|
const size_t mip_size = CalcImageSize( pic->type, width, height, 1 );
|
||||||
|
|
||||||
VkBufferImageCopy region = {0};
|
VkBufferImageCopy region = {0};
|
||||||
region.bufferOffset = staging_offset;
|
region.bufferOffset = 0;
|
||||||
region.bufferRowLength = 0;
|
region.bufferRowLength = 0;
|
||||||
region.bufferImageHeight = 0;
|
region.bufferImageHeight = 0;
|
||||||
region.imageSubresource = (VkImageSubresourceLayers){
|
region.imageSubresource = (VkImageSubresourceLayers){
|
||||||
@ -602,20 +600,22 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
|||||||
.depth = 1,
|
.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 )
|
if ( mip < mipCount - 1 )
|
||||||
{
|
{
|
||||||
BuildMipMap( buf, width, height, 1, tex->flags );
|
BuildMipMap( buf, width, height, 1, tex->flags );
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO we could do this only once w/ region array
|
R_VkStagingUnlockToImage(&staging, ®ion, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, tex->vk.image.image);
|
||||||
vkCmdCopyBufferToImage(cmdbuf, g_vk_buffers.staging.buffer, tex->vk.image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
|
||||||
|
|
||||||
staging_offset += mip_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R_VkStagingCommit(cmdbuf);
|
||||||
|
|
||||||
// 5.2 image:layout:DST -> image:layout:SAMPLED
|
// 5.2 image:layout:DST -> image:layout:SAMPLED
|
||||||
// 5.2.1 transitionToLayout(DST -> SHADER_READ_ONLY)
|
// 5.2.1 transitionToLayout(DST -> SHADER_READ_ONLY)
|
||||||
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user