diff --git a/ref_vk/vk_image.c b/ref_vk/vk_image.c new file mode 100644 index 00000000..e587f7b2 --- /dev/null +++ b/ref_vk/vk_image.c @@ -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}; +} diff --git a/ref_vk/vk_image.h b/ref_vk/vk_image.h new file mode 100644 index 00000000..78c5916e --- /dev/null +++ b/ref_vk/vk_image.h @@ -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); diff --git a/ref_vk/vk_ray_model.c b/ref_vk/vk_ray_model.c index 210606d6..5667d08e 100644 --- a/ref_vk/vk_ray_model.c +++ b/ref_vk/vk_ray_model.c @@ -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; diff --git a/ref_vk/vk_rtx.c b/ref_vk/vk_rtx.c index e14e6b23..6b4d9ba5 100644 --- a/ref_vk/vk_rtx.c +++ b/ref_vk/vk_rtx.c @@ -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); diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index a47083fd..47cd3dd2 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -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, ®ion); + vkCmdCopyBufferToImage(vk_core.cb_tex, vk_core.staging.buffer, tex->vk.image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); 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]; diff --git a/ref_vk/vk_textures.h b/ref_vk/vk_textures.h index b4c8fb81..14ae9720 100644 --- a/ref_vk/vk_textures.h +++ b/ref_vk/vk_textures.h @@ -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);