deduplicate creation of VkImages

This commit is contained in:
Ivan Avdeev 2021-11-21 13:40:11 -08:00
parent dc3e75bd44
commit 714d825956
6 changed files with 140 additions and 144 deletions

59
ref_vk/vk_image.c Normal file
View File

@ -0,0 +1,59 @@
#include "vk_image.h"
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
xvk_image_t image;
VkMemoryRequirements memreq;
VkImageViewCreateInfo ivci = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
VkImageCreateInfo ici = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.extent.width = create->width,
.extent.height = create->height,
.extent.depth = 1,
.mipLevels = create->mips,
.arrayLayers = 1,
.format = create->format,
.tiling = create->tiling,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.usage = create->usage,
.samples = VK_SAMPLE_COUNT_1_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image));
if (create->debug_name)
SET_DEBUG_NAME(image.image, VK_OBJECT_TYPE_IMAGE, create->debug_name);
vkGetImageMemoryRequirements(vk_core.device, image.image, &memreq);
image.devmem = allocateDeviceMemory(memreq, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
XVK_CHECK(vkBindImageMemory(vk_core.device, image.image, image.devmem.device_memory, 0));
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = ici.format;
ivci.image = image.image;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = ici.mipLevels;
ivci.subresourceRange.baseArrayLayer = 0;
ivci.subresourceRange.layerCount = 1;
ivci.components = (VkComponentMapping){0, 0, 0, create->has_alpha ? 0 : VK_COMPONENT_SWIZZLE_ONE};
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view));
if (create->debug_name)
SET_DEBUG_NAME(image.view, VK_OBJECT_TYPE_IMAGE_VIEW, create->debug_name);
image.width = create->width;
image.height = create->height;
image.mips = create->mips;
return image;
}
void XVK_ImageDestroy(xvk_image_t *img) {
vkDestroyImageView(vk_core.device, img->view, NULL);
vkDestroyImage(vk_core.device, img->image, NULL);
freeDeviceMemory(&img->devmem);
*img = (xvk_image_t){0};
}

26
ref_vk/vk_image.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include "vk_core.h"
typedef struct {
// FIXME better memory allocation
// OCHEN PLOHO
device_memory_t devmem;
VkImage image;
VkImageView view;
uint32_t width, height;
int mips;
} xvk_image_t;
typedef struct {
const char *debug_name;
uint32_t width, height;
VkFormat format;
VkImageTiling tiling;
VkImageUsageFlags usage;
int mips;
qboolean has_alpha;
} xvk_image_create_t;
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create);
void XVK_ImageDestroy(xvk_image_t *img);

View File

@ -136,7 +136,7 @@ void XVK_RayModel_Validate( void ) {
const vk_kusok_data_t *kusok = kusochki + j;
const vk_texture_t *tex = findTexture(kusok->tex_base_color);
ASSERT(tex);
ASSERT(tex->vk.image_view != VK_NULL_HANDLE);
ASSERT(tex->vk.image.view != VK_NULL_HANDLE);
// uint32_t index_offset;
// uint32_t vertex_offset;

View File

@ -80,12 +80,12 @@ enum {
};
typedef struct {
vk_image_t denoised;
vk_image_t base_color;
vk_image_t diffuse_gi;
vk_image_t specular;
vk_image_t additive;
vk_image_t normals;
xvk_image_t denoised;
xvk_image_t base_color;
xvk_image_t diffuse_gi;
xvk_image_t specular;
xvk_image_t additive;
xvk_image_t normals;
} xvk_ray_frame_images_t;
static struct {
@ -616,9 +616,9 @@ static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render
// TODO: move this to vk_texture.c
for (int i = 0; i < MAX_TEXTURES; ++i) {
const vk_texture_t *texture = findTexture(i);
const qboolean exists = texture->vk.image_view != VK_NULL_HANDLE;
const qboolean exists = texture->vk.image.view != VK_NULL_HANDLE;
dii_all_textures[i].sampler = vk_core.default_sampler; // FIXME on AMD using pImmutableSamplers leads to NEAREST filtering ??. VK_NULL_HANDLE;
dii_all_textures[i].imageView = exists ? texture->vk.image_view : findTexture(tglob.defaultTexture)->vk.image_view;
dii_all_textures[i].imageView = exists ? texture->vk.image.view : findTexture(tglob.defaultTexture)->vk.image.view;
ASSERT(dii_all_textures[i].imageView != VK_NULL_HANDLE);
dii_all_textures[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
@ -1248,30 +1248,31 @@ qboolean VK_RayInit( void )
createPipeline();
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
g_rtx.frames[i].denoised = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT );
SET_DEBUG_NAMEF(g_rtx.frames[i].denoised.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] denoised", i);
g_rtx.frames[i].base_color = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R8G8B8A8_UNORM,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].base_color.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] base_color", i);
g_rtx.frames[i].diffuse_gi = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].diffuse_gi.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] diffuse_gi", i);
g_rtx.frames[i].specular = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].specular.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] specular", i);
g_rtx.frames[i].additive = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].additive.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] additive", i);
#define CREATE_GBUFFER_IMAGE(name, format_, add_usage_bits) \
do { \
char debug_name[64]; \
const xvk_image_create_t create = { \
.debug_name = debug_name, \
.width = FRAME_WIDTH, \
.height = FRAME_HEIGHT, \
.mips = 1, \
.format = format_, \
.tiling = VK_IMAGE_TILING_OPTIMAL, \
.usage = VK_IMAGE_USAGE_STORAGE_BIT | add_usage_bits, \
.has_alpha = true, \
}; \
Q_snprintf(debug_name, sizeof(debug_name), "rtx frames[%d] " # name, i); \
g_rtx.frames[i].name = XVK_ImageCreate(&create); \
} while(0)
CREATE_GBUFFER_IMAGE(denoised, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
CREATE_GBUFFER_IMAGE(base_color, VK_FORMAT_R8G8B8A8_UNORM, 0);
CREATE_GBUFFER_IMAGE(diffuse_gi, VK_FORMAT_R16G16B16A16_SFLOAT, 0);
CREATE_GBUFFER_IMAGE(specular, VK_FORMAT_R16G16B16A16_SFLOAT, 0);
CREATE_GBUFFER_IMAGE(additive, VK_FORMAT_R16G16B16A16_SFLOAT, 0);
// TODO make sure this format and usage is suppported
g_rtx.frames[i].normals = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SNORM,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
SET_DEBUG_NAMEF(g_rtx.frames[i].normals.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] normals", i);
CREATE_GBUFFER_IMAGE(normals, VK_FORMAT_R16G16B16A16_SNORM, 0);
#undef CREATE_GBUFFER_IMAGE
}
if (vk_core.debug) {
@ -1287,12 +1288,12 @@ void VK_RayShutdown( void ) {
ASSERT(vk_core.rtx);
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
VK_ImageDestroy(&g_rtx.frames[i].denoised);
VK_ImageDestroy(&g_rtx.frames[i].base_color);
VK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
VK_ImageDestroy(&g_rtx.frames[i].specular);
VK_ImageDestroy(&g_rtx.frames[i].additive);
VK_ImageDestroy(&g_rtx.frames[i].normals);
XVK_ImageDestroy(&g_rtx.frames[i].denoised);
XVK_ImageDestroy(&g_rtx.frames[i].base_color);
XVK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
XVK_ImageDestroy(&g_rtx.frames[i].specular);
XVK_ImageDestroy(&g_rtx.frames[i].additive);
XVK_ImageDestroy(&g_rtx.frames[i].normals);
}
vkDestroyPipeline(vk_core.device, g_rtx.pipeline, NULL);

View File

@ -445,8 +445,7 @@ static void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, in
}
}
static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
{
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) {
const VkFormat format = VK_GetFormat(pic->type);
const VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
const VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@ -475,33 +474,18 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
// if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA ))
// data = GL_ApplyFilter( data, tex->width, tex->height );
// 1. Create VkImage w/ usage = DST|SAMPLED, layout=UNDEFINED
{
VkImageCreateInfo image_create_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.extent.width = pic->width,
.extent.height = pic->height,
.extent.depth = 1,
const xvk_image_create_t create = {
.debug_name = tex->name,
.width = pic->width,
.height = pic->height,
.mips = mipCount,
.format = format,
.mipLevels = mipCount,
.arrayLayers = 1,
.tiling = tiling,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.usage = usage,
.samples = VK_SAMPLE_COUNT_1_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.has_alpha = pic->flags & IMAGE_HAS_ALPHA,
};
XVK_CHECK(vkCreateImage(vk_core.device, &image_create_info, NULL, &tex->vk.image));
SET_DEBUG_NAME(tex->vk.image, VK_OBJECT_TYPE_IMAGE, tex->name);
}
// 2. Alloc mem for VkImage and bind it (DEV_LOCAL)
{
VkMemoryRequirements memreq;
vkGetImageMemoryRequirements(vk_core.device, tex->vk.image, &memreq);
tex->vk.device_memory = allocateDeviceMemory(memreq, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
XVK_CHECK(vkBindImageMemory(vk_core.device, tex->vk.image, tex->vk.device_memory.device_memory, tex->vk.device_memory.offset));
tex->vk.image = XVK_ImageCreate(&create);
}
{
@ -517,7 +501,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
// 5.1.1 transitionToLayout(UNDEFINED -> DST)
VkImageMemoryBarrier image_barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = tex->vk.image,
.image = tex->vk.image.image,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
@ -568,7 +552,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
}
// TODO we could do this only once w/ region array
vkCmdCopyBufferToImage(vk_core.cb_tex, vk_core.staging.buffer, tex->vk.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
vkCmdCopyBufferToImage(vk_core.cb_tex, vk_core.staging.buffer, tex->vk.image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
staging_offset += mip_size;
}
@ -603,28 +587,13 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
XVK_CHECK(vkQueueWaitIdle(vk_core.queue));
}
{
VkImageViewCreateInfo ivci = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = format;
ivci.image = tex->vk.image;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = mipCount;
ivci.subresourceRange.baseArrayLayer = 0;
ivci.subresourceRange.layerCount = 1;
ivci.components = (VkComponentMapping){0, 0, 0, (pic->flags & IMAGE_HAS_ALPHA) ? 0 : VK_COMPONENT_SWIZZLE_ONE};
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &tex->vk.image_view));
SET_DEBUG_NAME(tex->vk.image_view, VK_OBJECT_TYPE_IMAGE_VIEW, tex->name);
}
// TODO how should we approach this:
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
// - update descriptor sets in batch?
if (vk_desc.next_free != MAX_TEXTURES)
{
VkDescriptorImageInfo dii_tex = {
.imageView = tex->vk.image_view,
.imageView = tex->vk.image.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
};
VkWriteDescriptorSet wds[] = { {
@ -707,7 +676,7 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
// upload texture
VK_ProcessImage( tex, pic );
if( !VK_UploadTexture( tex, pic ))
if( !uploadTexture( tex, pic ))
{
memset( tex, 0, sizeof( vk_texture_t ));
gEngine.FS_FreeImage( pic ); // release source texture
@ -756,7 +725,7 @@ void VK_FreeTexture( unsigned int texnum ) {
ASSERT( tex != NULL );
// already freed?
if( !tex->vk.image ) return;
if( !tex->vk.image.image ) return;
// debug
if( !tex->name[0] )
@ -787,9 +756,7 @@ void VK_FreeTexture( unsigned int texnum ) {
gEngine.FS_FreeImage( tex->original );
*/
vkDestroyImageView(vk_core.device, tex->vk.image_view, NULL);
vkDestroyImage(vk_core.device, tex->vk.image, NULL);
freeDeviceMemory(&tex->vk.device_memory);
XVK_ImageDestroy(&tex->vk.image);
memset(tex, 0, sizeof(*tex));
}
@ -821,7 +788,7 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
VK_ProcessImage( tex, pic );
if( !VK_UploadTexture( tex, pic ))
if( !uploadTexture( tex, pic ))
{
memset( tex, 0, sizeof( vk_texture_t ));
return 0;
@ -834,51 +801,6 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
return (tex - vk_textures);
}
vk_image_t VK_ImageCreate(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage) {
vk_image_t image;
VkMemoryRequirements memreq;
VkImageViewCreateInfo ivci = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
VkImageCreateInfo ici = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.extent.width = width,
.extent.height = height,
.extent.depth = 1,
.mipLevels = 1,
.arrayLayers = 1,
.format = format,
.tiling = tiling,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.usage = usage,
.samples = VK_SAMPLE_COUNT_1_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
};
XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image));
vkGetImageMemoryRequirements(vk_core.device, image.image, &memreq);
image.devmem = allocateDeviceMemory(memreq, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
XVK_CHECK(vkBindImageMemory(vk_core.device, image.image, image.devmem.device_memory, 0));
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.format = ici.format;
ivci.image = image.image;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.levelCount = 1;
ivci.subresourceRange.layerCount = 1;
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view));
return image;
}
void VK_ImageDestroy(vk_image_t *img) {
vkDestroyImageView(vk_core.device, img->view, NULL);
vkDestroyImage(vk_core.device, img->image, NULL);
freeDeviceMemory(&img->devmem);
*img = (vk_image_t){0};
}
int XVK_TextureLookupF( const char *fmt, ...) {
int tex_id = 0;
char buffer[1024];

View File

@ -1,5 +1,6 @@
#pragma once
#include "vk_core.h"
#include "vk_image.h"
#include "xash3d_types.h"
#include "const.h"
@ -14,9 +15,7 @@ typedef struct vk_texture_s
uint texnum;
struct {
VkImage image;
VkImageView image_view;
device_memory_t device_memory;
xvk_image_t image;
VkDescriptorSet descriptor;
} vk;
@ -70,14 +69,3 @@ int XVK_TextureLookupF( const char *fmt, ...);
#define VK_LoadTextureInternal( name, pic, flags ) VK_LoadTextureFromBuffer( name, pic, flags, false )
void XVK_SetupSky( const char *skyboxname );
typedef struct {
// FIXME better memory allocation
// OCHEN PLOHO
device_memory_t devmem;
VkImage image;
VkImageView view;
} vk_image_t;
vk_image_t VK_ImageCreate(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage);
void VK_ImageDestroy(vk_image_t *img);