From 714d825956031fe5471c318842576c7eedbcd18c Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Sun, 21 Nov 2021 13:40:11 -0800 Subject: [PATCH 1/9] deduplicate creation of VkImages --- ref_vk/vk_image.c | 59 +++++++++++++++++++++++ ref_vk/vk_image.h | 26 ++++++++++ ref_vk/vk_ray_model.c | 2 +- ref_vk/vk_rtx.c | 73 ++++++++++++++-------------- ref_vk/vk_textures.c | 108 ++++++------------------------------------ ref_vk/vk_textures.h | 16 +------ 6 files changed, 140 insertions(+), 144 deletions(-) create mode 100644 ref_vk/vk_image.c create mode 100644 ref_vk/vk_image.h 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); From 1ad13817fe70a45ffec259c8ca250204a5823a31 Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Sun, 21 Nov 2021 14:53:51 -0800 Subject: [PATCH 2/9] add cubemap support; add misaligned skybox --- ref_vk/shaders/ray.rmiss | 11 ++- ref_vk/shaders/ray_interop.h | 2 +- ref_vk/vk_image.c | 7 +- ref_vk/vk_image.h | 3 +- ref_vk/vk_rtx.c | 27 +++++-- ref_vk/vk_textures.c | 136 +++++++++++++++++++++++------------ ref_vk/vk_textures.h | 4 +- 7 files changed, 125 insertions(+), 65 deletions(-) diff --git a/ref_vk/shaders/ray.rmiss b/ref_vk/shaders/ray.rmiss index 058b318a..751872e3 100644 --- a/ref_vk/shaders/ray.rmiss +++ b/ref_vk/shaders/ray.rmiss @@ -5,8 +5,9 @@ #include "ray_common.glsl" #include "ray_kusochki.glsl" -layout (constant_id = 6) const uint MAX_TEXTURES = 4096; -layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES]; +//layout (constant_id = 6) const uint MAX_TEXTURES = 4096; +//layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES]; +layout (set = 0, binding = 13) uniform samplerCube skybox; layout (set = 0, binding = 7/*, align=4*/) uniform UBOLights { Lights lights; }; layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload; @@ -19,9 +20,5 @@ void main() { payload.base_color = vec3(1., 0., 1.); payload.kusok_index = -1; payload.material_index = 0; - payload.emissive = vec3(1., 0., 1.); - - const uint tex_skyplane = lights.skybox_up; - const vec2 sky_uv = gl_WorldRayDirectionEXT.xy * .5 + .5; - payload.emissive = texture(textures[nonuniformEXT(tex_skyplane)], sky_uv).rgb; + payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb; } diff --git a/ref_vk/shaders/ray_interop.h b/ref_vk/shaders/ray_interop.h index a9c12dd1..d044fb9c 100644 --- a/ref_vk/shaders/ray_interop.h +++ b/ref_vk/shaders/ray_interop.h @@ -71,7 +71,7 @@ struct EmissiveKusok { struct Lights { uint num_kusochki; uint num_point_lights; - uint skybox_rt, skybox_bk, skybox_lf, skybox_ft, skybox_up, skybox_dn; + PAD(2) STRUCT EmissiveKusok kusochki[MAX_EMISSIVE_KUSOCHKI]; STRUCT PointLight point_lights[MAX_POINT_LIGHTS]; }; diff --git a/ref_vk/vk_image.c b/ref_vk/vk_image.c index e587f7b2..0d4fecbd 100644 --- a/ref_vk/vk_image.c +++ b/ref_vk/vk_image.c @@ -12,13 +12,14 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) { .extent.height = create->height, .extent.depth = 1, .mipLevels = create->mips, - .arrayLayers = 1, + .arrayLayers = create->layers, .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, + .flags = create->is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0, }; XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image)); @@ -30,14 +31,14 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) { 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.viewType = create->is_cubemap ? VK_IMAGE_VIEW_TYPE_CUBE : 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.subresourceRange.layerCount = ici.arrayLayers; ivci.components = (VkComponentMapping){0, 0, 0, create->has_alpha ? 0 : VK_COMPONENT_SWIZZLE_ONE}; XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view)); diff --git a/ref_vk/vk_image.h b/ref_vk/vk_image.h index 78c5916e..35e0a299 100644 --- a/ref_vk/vk_image.h +++ b/ref_vk/vk_image.h @@ -15,11 +15,12 @@ typedef struct { typedef struct { const char *debug_name; uint32_t width, height; + int mips, layers; VkFormat format; VkImageTiling tiling; VkImageUsageFlags usage; - int mips; qboolean has_alpha; + qboolean is_cubemap; } xvk_image_create_t; xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create); diff --git a/ref_vk/vk_rtx.c b/ref_vk/vk_rtx.c index 6b4d9ba5..70f8d447 100644 --- a/ref_vk/vk_rtx.c +++ b/ref_vk/vk_rtx.c @@ -76,6 +76,8 @@ enum { RayDescBinding_Dest_ImageAdditive = 11, RayDescBinding_Dest_ImageNormals = 12, + RayDescBinding_SkyboxCube = 13, + RayDescBinding_COUNT }; @@ -613,6 +615,12 @@ static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render g_rtx.desc_values[RayDescBinding_Textures].image_array = dii_all_textures; + g_rtx.desc_values[RayDescBinding_SkyboxCube].image = (VkDescriptorImageInfo){ + .sampler = vk_core.default_sampler, + .imageView = tglob.skybox_cube.vk.image.view ? tglob.skybox_cube.vk.image.view : tglob.cubemap_placeholder.vk.image.view, + .imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + }; + // TODO: move this to vk_texture.c for (int i = 0; i < MAX_TEXTURES; ++i) { const vk_texture_t *texture = findTexture(i); @@ -793,13 +801,6 @@ static void updateLights( void ) dst->environment = !!(src->flags & LightFlag_Environment); } - - lights->skybox_rt = tglob.skyboxTextures[0]; - lights->skybox_bk = tglob.skyboxTextures[1]; - lights->skybox_lf = tglob.skyboxTextures[2]; - lights->skybox_ft = tglob.skyboxTextures[3]; - lights->skybox_up = tglob.skyboxTextures[4]; - lights->skybox_dn = tglob.skyboxTextures[5]; } } @@ -1148,6 +1149,16 @@ static void createLayouts( void ) { .pImmutableSamplers = NULL, //samplers, }; + g_rtx.desc_bindings[RayDescBinding_SkyboxCube] = (VkDescriptorSetLayoutBinding){ + .binding = RayDescBinding_SkyboxCube, + .descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, + // FIXME on AMD using immutable samplers leads to nearest filtering ???! + .pImmutableSamplers = NULL, //samplers, + }; + + // for (int i = 0; i < ARRAYSIZE(samplers); ++i) // samplers[i] = vk_core.default_sampler; @@ -1256,10 +1267,12 @@ qboolean VK_RayInit( void ) .width = FRAME_WIDTH, \ .height = FRAME_HEIGHT, \ .mips = 1, \ + .layers = 1, \ .format = format_, \ .tiling = VK_IMAGE_TILING_OPTIMAL, \ .usage = VK_IMAGE_USAGE_STORAGE_BIT | add_usage_bits, \ .has_alpha = true, \ + .is_cubemap = false, \ }; \ Q_snprintf(debug_name, sizeof(debug_name), "rtx frames[%d] " # name, i); \ g_rtx.frames[i].name = XVK_ImageCreate(&create); \ diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index 47cd3dd2..208a985b 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -230,6 +230,8 @@ static void VK_ProcessImage( vk_texture_t *tex, rgbdata_t *pic ) } } +static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap); + static void VK_CreateInternalTextures( void ) { int dx2, dy, d; @@ -290,6 +292,22 @@ static void VK_CreateInternalTextures( void ) // cinematic dummy pic = Common_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR ); tglob.cinTexture = VK_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP ); + + { + rgbdata_t *sides[6]; + pic = Common_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); + for( x = 0; x < 16; x++ ) + ((uint *)pic->buffer)[x] = 0xFFFFFFFF; + + sides[0] = pic; + sides[1] = pic; + sides[2] = pic; + sides[3] = pic; + sides[4] = pic; + sides[5] = pic; + + uploadTexture( &tglob.cubemap_placeholder, sides, 6, true ); + } } static VkFormat VK_GetFormat(pixformat_t format) @@ -445,45 +463,67 @@ static void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, in } } -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; - byte *buf = pic->buffer; - +static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap) { + const VkFormat format = VK_GetFormat(layers[0]->type); int mipCount = 0; // TODO non-rbga textures - // TODO cubemaps - if (!pic->buffer) - return false; + for (int i = 0; i < num_layers; ++i) { + if (!layers[i]->buffer) { + gEngine.Con_Printf(S_ERROR "Texture %s layer %d missing buffer\n", tex->name, i); + return false; + } - tex->width = pic->width; - tex->height = pic->height; - mipCount = CalcMipmapCount( tex, ( buf != NULL )); + if (i == 0) + continue; - gEngine.Con_Reportf("Uploading texture %s, mips=%d\n", tex->name, mipCount); + if (layers[0]->type != layers[i]->type) { + gEngine.Con_Printf(S_ERROR "Texture %s layer %d has type %d inconsistent with layer 0 type %d\n", tex->name, i, layers[i]->type, layers[0]->type); + return false; + } + + if (layers[0]->width != layers[i]->width || layers[0]->height != layers[i]->height) { + gEngine.Con_Printf(S_ERROR "Texture %s layer %d has resolution %dx%d inconsistent with layer 0 resolution %dx%d\n", + tex->name, i, layers[i]->width, layers[i]->height, layers[0]->width, layers[0]->height); + return false; + } + + if ((layers[0]->flags ^ layers[i]->flags) & IMAGE_HAS_ALPHA) { + gEngine.Con_Printf(S_ERROR "Texture %s layer %d has_alpha=%d inconsistent with layer 0 has_alpha=%d\n", + tex->name, i, + !!(layers[i]->flags & IMAGE_HAS_ALPHA), + !!(layers[0]->flags & IMAGE_HAS_ALPHA)); + } + } + + tex->width = layers[0]->width; + tex->height = layers[0]->height; + mipCount = CalcMipmapCount( tex, true); + + gEngine.Con_Reportf("Uploading texture %s, mips=%d, layers=%d\n", tex->name, mipCount, layers); // TODO this vvv // // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides - // if(( tex->depth == 1 ) && (( pic->width != tex->width ) || ( pic->height != tex->height ))) - // data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap ); + // if(( tex->depth == 1 ) && (( layers->width != tex->width ) || ( layers->height != tex->height ))) + // data = GL_ResampleTexture( buf, layers->width, layers->height, tex->width, tex->height, normalMap ); // else data = buf; - // if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA )) + // if( !ImageDXT( layers->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( layers->flags, IMAGE_ONEBIT_ALPHA )) // data = GL_ApplyFilter( data, tex->width, tex->height ); { const xvk_image_create_t create = { .debug_name = tex->name, - .width = pic->width, - .height = pic->height, + .width = tex->width, + .height = tex->height, .mips = mipCount, + .layers = num_layers, .format = format, - .tiling = tiling, - .usage = usage, - .has_alpha = pic->flags & IMAGE_HAS_ALPHA, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .has_alpha = layers[0]->flags & IMAGE_HAS_ALPHA, + .is_cubemap = cubemap, }; tex->vk.image = XVK_ImageCreate(&create); } @@ -511,7 +551,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) { .baseMipLevel = 0, .levelCount = mipCount, .baseArrayLayer = 0, - .layerCount = 1, + .layerCount = num_layers, }}; XVK_CHECK(vkBeginCommandBuffer(vk_core.cb_tex, &beginfo)); @@ -521,9 +561,10 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) { 0, 0, NULL, 0, NULL, 1, &image_barrier); // 5.1.2 copyBufferToImage for all mip levels - { - for (int mip = 0; mip < mipCount; ++mip) - { + for (int layer = 0; layer < num_layers; ++layer) { + for (int mip = 0; mip < mipCount; ++mip) { + const rgbdata_t *const pic = layers[layer]; + byte *buf = pic->buffer; const int width = Q_max( 1, ( pic->width >> mip )); const int height = Q_max( 1, ( pic->height >> mip )); const size_t mip_size = CalcImageSize( pic->type, width, height, 1 ); @@ -535,7 +576,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) { region.imageSubresource = (VkImageSubresourceLayers){ .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .mipLevel = mip, - .baseArrayLayer = 0, + .baseArrayLayer = layer, .layerCount = 1, }; region.imageExtent = (VkExtent3D){ @@ -569,7 +610,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) { .baseMipLevel = 0, .levelCount = mipCount, .baseArrayLayer = 0, - .layerCount = 1, + .layerCount = num_layers, }; vkCmdPipelineBarrier(vk_core.cb_tex, VK_PIPELINE_STAGE_TRANSFER_BIT, @@ -676,7 +717,7 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) // upload texture VK_ProcessImage( tex, pic ); - if( !uploadTexture( tex, pic )) + if( !uploadTexture( tex, &pic, 1, false )) { memset( tex, 0, sizeof( vk_texture_t )); gEngine.FS_FreeImage( pic ); // release source texture @@ -788,7 +829,7 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags VK_ProcessImage( tex, pic ); - if( !uploadTexture( tex, pic )) + if( !uploadTexture( tex, &pic, 1, false )) { memset( tex, 0, sizeof( vk_texture_t )); return 0; @@ -814,20 +855,12 @@ int XVK_TextureLookupF( const char *fmt, ...) { return tex_id; } -static void unloadSkybox( void ) -{ - int i; - - // release old skybox - for( i = 0; i < 6; i++ ) - { - if( !tglob.skyboxTextures[i] ) continue; - VK_FreeTexture( tglob.skyboxTextures[i] ); +static void unloadSkybox( void ) { + if (tglob.skybox_cube.vk.image.image) { + XVK_ImageDestroy(&tglob.skybox_cube.vk.image); + memset(&tglob.skybox_cube, 0, sizeof(tglob.skybox_cube)); } - tglob.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes) - - memset( tglob.skyboxTextures, 0, sizeof( tglob.skyboxTextures )); tglob.fCustomSkybox = false; } @@ -880,6 +913,7 @@ void XVK_SetupSky( const char *skyboxname ) char loadname[MAX_STRING]; char sidename[MAX_STRING]; int i, result, len; + rgbdata_t *sides[6]; if( !COM_CheckString( skyboxname )) { @@ -915,18 +949,30 @@ void XVK_SetupSky( const char *skyboxname ) Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] ); else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] ); - tglob.skyboxTextures[i] = VK_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY ); - if( !tglob.skyboxTextures[i] ) break; + sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0); + if (!sides[i]) + break; + gEngine.Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " ); } - if( i == 6 ) - { + for (int j = 0; j < i; ++j) + gEngine.FS_FreeImage( sides[j] ); // release source texture + + if( i != 6 ) + goto fail; + + if( !Common_CheckTexName( loadname )) + goto fail; + + // needed? VK_ProcessImage( tex, pic ); + if (uploadTexture(&tglob.skybox_cube, sides, 6, true)) { tglob.fCustomSkybox = true; gEngine.Con_DPrintf( "done\n" ); return; // loaded } +fail: gEngine.Con_DPrintf( "^2failed\n" ); unloadSkybox(); } diff --git a/ref_vk/vk_textures.h b/ref_vk/vk_textures.h index 14ae9720..37d99cf8 100644 --- a/ref_vk/vk_textures.h +++ b/ref_vk/vk_textures.h @@ -36,13 +36,15 @@ typedef struct vk_textures_global_s int alphaskyTexture; // quake1 alpha-sky layer int lightmapTextures[MAX_LIGHTMAPS]; int dlightTexture; // custom dlight texture - int skyboxTextures[6]; // skybox sides int cinTexture; // cinematic texture int skytexturenum; // this not a gl_texturenum! int skyboxbasenum; // start with 5800 FIXME remove this, lewa says this is a GL1 hack qboolean fCustomSkybox; // TODO do we need this for anything? + + vk_texture_t skybox_cube; + vk_texture_t cubemap_placeholder; } vk_textures_global_t; // TODO rename this consistently From 9920dc667499758c4480f17ebf9b5add7e10416a Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Tue, 23 Nov 2021 09:07:21 -0800 Subject: [PATCH 3/9] unload cubemaps --- ref_vk/vk_textures.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index 208a985b..16790d02 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -48,11 +48,18 @@ void initTextures( void ) */ } +static void unloadSkybox( void ); + void destroyTextures( void ) { for( unsigned int i = 0; i < vk_numTextures; i++ ) VK_FreeTexture( i ); + unloadSkybox(); + + XVK_ImageDestroy(&tglob.cubemap_placeholder.vk.image); + memset(&tglob.cubemap_placeholder, 0, sizeof(tglob.cubemap_placeholder)); + //memset( tglob.lightmapTextures, 0, sizeof( tglob.lightmapTextures )); memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable )); memset( vk_textures, 0, sizeof( vk_textures )); From 12565a35a194b3b6404ecc2b8c2ba94409b07332 Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Tue, 23 Nov 2021 09:07:58 -0800 Subject: [PATCH 4/9] reorient skyboxes to vulkan spec --- ref_vk/vk_textures.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index 16790d02..be29b6db 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -871,8 +871,17 @@ static void unloadSkybox( void ) { tglob.fCustomSkybox = false; } -static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" }; -//static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 }; +static struct { + const char *suffix; + uint flags; +} g_skybox_info[6] = { + {"rt", IMAGE_ROT_90}, + {"lf", IMAGE_FLIP_Y | IMAGE_ROT_90 | IMAGE_FLIP_X}, + {"bk", IMAGE_FLIP_Y}, + {"ft", IMAGE_FLIP_X}, + {"up", IMAGE_ROT_90}, + {"dn", IMAGE_ROT_90}, +}; #define SKYBOX_MISSED 0 #define SKYBOX_HLSTYLE 1 @@ -891,7 +900,7 @@ static int CheckSkybox( const char *name ) for( j = 0; j < 6; j++ ) { // build side name - sidename = va( "%s%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] ); + sidename = va( "%s%s.%s", name, g_skybox_info[j].suffix, skybox_ext[i] ); if( gEngine.FS_FileExists( sidename, false )) num_checked_sides++; @@ -903,7 +912,7 @@ static int CheckSkybox( const char *name ) for( j = 0; j < 6; j++ ) { // build side name - sidename = va( "%s_%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] ); + sidename = va( "%s_%s.%s", name, g_skybox_info[j].suffix, skybox_ext[i] ); if( gEngine.FS_FileExists( sidename, false )) num_checked_sides++; } @@ -953,14 +962,22 @@ void XVK_SetupSky( const char *skyboxname ) for( i = 0; i < 6; i++ ) { if( result == SKYBOX_HLSTYLE ) - Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] ); - else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] ); + Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, g_skybox_info[i].suffix ); + else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, g_skybox_info[i].suffix ); sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0); - if (!sides[i]) + if (!sides[i] || !sides[i]->buffer) break; - gEngine.Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " ); + + { + uint img_flags = g_skybox_info[i].flags; + // we need to expand image into RGBA buffer + if( sides[i]->type == PF_INDEXED_24 || sides[i]->type == PF_INDEXED_32 ) + img_flags |= IMAGE_FORCE_RGBA; + gEngine.Image_Process( &sides[i], 0, 0, img_flags, 0.f ); + } + gEngine.Con_DPrintf( "%s%s%s", skyboxname, g_skybox_info[i].suffix, i != 5 ? ", " : ". " ); } for (int j = 0; j < i; ++j) From a9d5e4dd2269c77515ba39527337d392694a7afe Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Thu, 25 Nov 2021 11:53:44 -0800 Subject: [PATCH 5/9] rtx: draw skybox on SURF_SKY surfaces only - change how shadows for environment lights work: should cast light only when hitting SURF_SKY - add SBT_RECORD_SIZE to specialization; need this for sky/shadow closest hit shader fix #140 --- ref_vk/shaders/ray.rchit | 38 ++++++++++++++++++++--------- ref_vk/shaders/ray.rgen | 44 +++++++++++++++++++++++++--------- ref_vk/shaders/ray.rmiss | 8 +------ ref_vk/shaders/ray_common.glsl | 7 +++++- ref_vk/shaders/ray_interop.h | 3 +++ ref_vk/shaders/shadow.rchit | 15 ++++++++++++ ref_vk/shaders/shadow.rmiss | 2 +- ref_vk/vk_brush.c | 8 ++++--- ref_vk/vk_light.c | 4 ++-- ref_vk/vk_ray_model.c | 10 ++++++++ ref_vk/vk_rtx.c | 22 ++++++++++++++++- ref_vk/vk_textures.c | 4 ++-- 12 files changed, 126 insertions(+), 39 deletions(-) create mode 100644 ref_vk/shaders/shadow.rchit diff --git a/ref_vk/shaders/ray.rchit b/ref_vk/shaders/ray.rchit index e7cb765e..193dd884 100644 --- a/ref_vk/shaders/ray.rchit +++ b/ref_vk/shaders/ray.rchit @@ -7,6 +7,7 @@ layout (constant_id = 6) const uint MAX_TEXTURES = 4096; layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES]; +layout (set = 0, binding = 13) uniform samplerCube skybox; layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload; @@ -79,6 +80,30 @@ void main() { const uint vi2 = uint(indices[first_index_offset+1]) + kusochki[kusok_index].vertex_offset; const uint vi3 = uint(indices[first_index_offset+2]) + kusochki[kusok_index].vertex_offset; + const vec3 pos[3] = { + gl_ObjectToWorldEXT * vec4(vertices[vi1].pos, 1.), + gl_ObjectToWorldEXT * vec4(vertices[vi2].pos, 1.), + gl_ObjectToWorldEXT * vec4(vertices[vi3].pos, 1.), + }; + // This one is supposed to be numerically better, but I can't see why + const vec3 hit_pos = pos[0] * (1. - bary.x - bary.y) + pos[1] * bary.x + pos[2] * bary.y; + //const vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT + + const uint tex_base_color = kusochki[kusok_index].tex_base_color; + if ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) { + payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT); + payload.base_color = vec3(0.); + payload.transmissiveness = 0.; + payload.normal = vec3(0.); + payload.geometry_normal = vec3(0.); + payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb; + payload.kusok_index = -1; + payload.roughness = 0.; + payload.metalness = 0.; + payload.material_index = tex_base_color; + return; + } + const vec3 n1 = vertices[vi1].normal; const vec3 n2 = vertices[vi2].normal; const vec3 n3 = vertices[vi3].normal; @@ -94,11 +119,6 @@ void main() { vertices[vi3].gl_tc, }; - const vec3 pos[3] = { - gl_ObjectToWorldEXT * vec4(vertices[vi1].pos, 1.), - gl_ObjectToWorldEXT * vec4(vertices[vi2].pos, 1.), - gl_ObjectToWorldEXT * vec4(vertices[vi3].pos, 1.), - }; const vec2 texture_uv_stationary = vertices[vi1].gl_tc * (1. - bary.x - bary.y) + vertices[vi2].gl_tc * bary.x + vertices[vi3].gl_tc * bary.y; const vec2 texture_uv = texture_uv_stationary + push_constants.time * kusochki[kusok_index].uv_speed; @@ -106,15 +126,11 @@ void main() { const float geom_normal_sign = sign(dot(real_geom_normal, -gl_WorldRayDirectionEXT)); const vec3 geom_normal = geom_normal_sign * real_geom_normal; - // This one is supposed to be numerically better, but I can't see why - const vec3 hit_pos = pos[0] * (1. - bary.x - bary.y) + pos[1] * bary.x + pos[2] * bary.y + geom_normal * normal_offset_fudge; - //const vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT + geom_normal * normal_offset_fudge; - const float ray_cone_width = payload.pixel_cone_spread_angle * payload.t_offset; vec4 uv_lods; computeAnisotropicEllipseAxes(hit_pos, /* TODO geom_?*/ normal, gl_WorldRayDirectionEXT, ray_cone_width, pos, uvs, texture_uv_stationary, uv_lods.xy, uv_lods.zw); - const uint tex_index = kusochki[kusok_index].tex_base_color; + const uint tex_index = tex_base_color; const vec4 tex_color = sampleTexture(tex_index, texture_uv, uv_lods); //const vec3 base_color = pow(tex_color.rgb, vec3(2.)); const vec3 base_color = ((push_constants.flags & PUSH_FLAG_LIGHTMAP_ONLY) != 0) ? vec3(1.) : tex_color.rgb;// pow(tex_color.rgb, vec3(2.)); @@ -135,7 +151,7 @@ void main() { // FIXME read alpha from texture - payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT); + payload.hit_pos_t = vec4(hit_pos + geom_normal * normal_offset_fudge, gl_HitTEXT); payload.base_color = base_color * kusochki[kusok_index].color.rgb; payload.transmissiveness = (1. - tex_color.a * kusochki[kusok_index].color.a); payload.normal = normal; diff --git a/ref_vk/shaders/ray.rgen b/ref_vk/shaders/ray.rgen index 2ec90d59..9c04b9b7 100644 --- a/ref_vk/shaders/ray.rgen +++ b/ref_vk/shaders/ray.rgen @@ -16,6 +16,7 @@ const float throughput_threshold = 1e-3; layout (constant_id = 4) const float LIGHT_GRID_CELL_SIZE = 256.; layout (constant_id = 5) const uint MAX_LIGHT_CLUSTERS = 32768; +layout (constant_id = 7) const uint SBT_RECORD_SIZE = 64; //const uint LIGHT_CLUSTER_SIZE = 2 + MAX_VISIBLE_POINT_LIGHTS + MAX_VISIBLE_SURFACE_LIGHTS; //const uint LIGHT_CLUSTER_NUM_DLIGHTS_OFFSET = 0; @@ -51,7 +52,7 @@ layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadEXT RayPayloadShadow payloa layout(location = PAYLOAD_LOCATION_ADDITIVE) rayPayloadEXT RayPayloadAdditive payload_additive; bool shadowed(vec3 pos, vec3 dir, float dist) { - payload_shadow.shadow = true; + payload_shadow.hit_type = SHADOW_HIT; const uint flags = 0 //| gl_RayFlagsCullFrontFacingTrianglesEXT //| gl_RayFlagsOpaqueEXT @@ -63,7 +64,24 @@ bool shadowed(vec3 pos, vec3 dir, float dist) { GEOMETRY_BIT_OPAQUE, 0, 0, SHADER_OFFSET_MISS_SHADOW, pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW); - return payload_shadow.shadow; + return payload_shadow.hit_type == SHADOW_HIT; +} + +// TODO join with just shadowed() +bool shadowedSky(vec3 pos, vec3 dir, float dist) { + payload_shadow.hit_type = SHADOW_HIT; + const uint flags = 0 + //| gl_RayFlagsCullFrontFacingTrianglesEXT + //| gl_RayFlagsOpaqueEXT + //| gl_RayFlagsTerminateOnFirstHitEXT + //| gl_RayFlagsSkipClosestHitShaderEXT + ; + traceRayEXT(tlas, + flags, + GEOMETRY_BIT_OPAQUE, + SHADER_OFFSET_HIT_SHADOW, SBT_RECORD_SIZE, SHADER_OFFSET_MISS_SHADOW, + pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW); + return payload_shadow.hit_type != SHADOW_SKY; } // This is an entry point for evaluation of all other BRDFs based on selected configuration (for direct light) @@ -182,9 +200,9 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate const float stopdot = lights.point_lights[i].color_stopdot.a; const vec3 dir = lights.point_lights[i].dir_stopdot2.xyz; const float stopdot2 = lights.point_lights[i].dir_stopdot2.a; - const bool environment = (lights.point_lights[i].environment == 0); + const bool not_environment = (lights.point_lights[i].environment == 0); - const vec3 light_dir = environment ? (origin_r.xyz - payload_opaque.hit_pos_t.xyz) : -dir; // TODO need to randomize sampling direction for environment soft shadow + const vec3 light_dir = not_environment ? (origin_r.xyz - payload_opaque.hit_pos_t.xyz) : -dir; // TODO need to randomize sampling direction for environment soft shadow const vec3 light_dir_norm = normalize(light_dir); const float light_dot = dot(light_dir_norm, payload_opaque.normal); if (light_dot < 1e-5) @@ -199,8 +217,8 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate spot_attenuation = (spot_dot - stopdot2) / (stopdot - stopdot2); float fdist = 1.f; - float light_dist = 1e6; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too? - if (environment) { + float light_dist = 1e4; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too? + if (not_environment) { #if 1 const float d2 = dot(light_dir, light_dir); const float r2 = origin_r.w * origin_r.w; @@ -221,7 +239,6 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate // if (dot(color,color) < color_culling_threshold) // continue; - // TODO split into diffuse and specular for denoiser vec3 ldiffuse, lspecular; evalSplitBRDF(payload_opaque.normal, light_dir_norm, view_dir, material, ldiffuse, lspecular); ldiffuse *= color; @@ -232,9 +249,14 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate if (dot(combined,combined) < color_culling_threshold) continue; - // TODO for environment light check that we've hit SURF_SKY - if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge)) - continue; + if (not_environment) { + if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge)) + continue; + } else { + // for environment light check that we've hit SURF_SKY + if (shadowedSky(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge)) + continue; + } diffuse += ldiffuse; specular += lspecular; @@ -365,7 +387,7 @@ void main() { vec3 additive = traceAdditive(origin, direction, payload_opaque.hit_pos_t.w <= 0. ? L : payload_opaque.hit_pos_t.w); // Sky/envmap - if (payload_opaque.hit_pos_t.w <= 0.) { + if (payload_opaque.kusok_index < 0) { if (bounce == 0) { out_additive += payload_opaque.emissive * color_factor + additive; } else { diff --git a/ref_vk/shaders/ray.rmiss b/ref_vk/shaders/ray.rmiss index 751872e3..af385020 100644 --- a/ref_vk/shaders/ray.rmiss +++ b/ref_vk/shaders/ray.rmiss @@ -1,15 +1,9 @@ #version 460 core -#extension GL_EXT_nonuniform_qualifier : enable #extension GL_GOOGLE_include_directive : require #include "ray_common.glsl" #include "ray_kusochki.glsl" -//layout (constant_id = 6) const uint MAX_TEXTURES = 4096; -//layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES]; -layout (set = 0, binding = 13) uniform samplerCube skybox; -layout (set = 0, binding = 7/*, align=4*/) uniform UBOLights { Lights lights; }; - layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload; void main() { @@ -20,5 +14,5 @@ void main() { payload.base_color = vec3(1., 0., 1.); payload.kusok_index = -1; payload.material_index = 0; - payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb; + payload.emissive = vec3(1., 0., 1.); } diff --git a/ref_vk/shaders/ray_common.glsl b/ref_vk/shaders/ray_common.glsl index cf9bc3df..652317a8 100644 --- a/ref_vk/shaders/ray_common.glsl +++ b/ref_vk/shaders/ray_common.glsl @@ -19,8 +19,13 @@ struct RayPayloadOpaque { vec4 debug; }; + +#define SHADOW_MISS 0 +#define SHADOW_HIT 1 +#define SHADOW_SKY 2 + struct RayPayloadShadow { - bool shadow; + uint hit_type; }; diff --git a/ref_vk/shaders/ray_interop.h b/ref_vk/shaders/ray_interop.h index d044fb9c..4d83cac4 100644 --- a/ref_vk/shaders/ray_interop.h +++ b/ref_vk/shaders/ray_interop.h @@ -32,6 +32,9 @@ layout (constant_id = 3) const uint MAX_VISIBLE_SURFACE_LIGHTS = 255; #define SHADER_OFFSET_HIT_REGULAR 0 #define SHADER_OFFSET_HIT_ALPHA_TEST 1 #define SHADER_OFFSET_HIT_ADDITIVE 2 +#define SHADER_OFFSET_HIT_SHADOW 3 + +#define KUSOK_MATERIAL_FLAG_SKYBOX 0x80000000 struct Kusok { uint index_offset; diff --git a/ref_vk/shaders/shadow.rchit b/ref_vk/shaders/shadow.rchit new file mode 100644 index 00000000..f759d2f6 --- /dev/null +++ b/ref_vk/shaders/shadow.rchit @@ -0,0 +1,15 @@ +#version 460 core +#extension GL_EXT_ray_tracing: require + +#include "ray_kusochki.glsl" +#include "ray_common.glsl" + +layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow; + +void main() { + const int instance_kusochki_offset = gl_InstanceCustomIndexEXT; + const int kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT; + const uint tex_base_color = kusochki[kusok_index].tex_base_color; + + payload_shadow.hit_type = ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) ? SHADOW_HIT : SHADOW_SKY ; +} diff --git a/ref_vk/shaders/shadow.rmiss b/ref_vk/shaders/shadow.rmiss index 4f684572..2a5fc9a8 100644 --- a/ref_vk/shaders/shadow.rmiss +++ b/ref_vk/shaders/shadow.rmiss @@ -6,5 +6,5 @@ layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow; void main() { - payload_shadow.shadow = false; + payload_shadow.hit_type = SHADOW_MISS; } diff --git a/ref_vk/vk_brush.c b/ref_vk/vk_brush.c index 7c987912..44297a24 100644 --- a/ref_vk/vk_brush.c +++ b/ref_vk/vk_brush.c @@ -382,8 +382,9 @@ static qboolean renderableSurface( const msurface_t *surf, int i ) { return false; } + // Explicitly enable SURF_SKY, otherwise they will be skipped by SURF_DRAWTILED if( FBitSet( surf->flags, SURF_DRAWSKY )) { - return false; + return true; } if( FBitSet( surf->flags, SURF_DRAWTILED )) { @@ -409,7 +410,6 @@ static model_sizes_t computeSizes( const model_t *mod ) { const msurface_t *surf = mod->surfaces + mod->firstmodelsurface + i; sizes.water_surfaces += !!(surf->flags & (SURF_DRAWTURB | SURF_DRAWTURB_QUADS)); - //sizes.sky_surfaces += !!(surf->flags & SURF_DRAWSKY); if (!renderableSurface(surf, i)) continue; @@ -487,7 +487,9 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) { model_geometry->material = kXVkMaterialSky; } else { model_geometry->material = kXVkMaterialRegular; - VK_CreateSurfaceLightmap( surf, mod ); + if (!FBitSet( surf->flags, SURF_DRAWTILED )) { + VK_CreateSurfaceLightmap( surf, mod ); + } } if (FBitSet( surf->flags, SURF_CONVEYOR )) { diff --git a/ref_vk/vk_light.c b/ref_vk/vk_light.c index 7158bdb9..183fc4f2 100644 --- a/ref_vk/vk_light.c +++ b/ref_vk/vk_light.c @@ -637,8 +637,8 @@ void VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const if (geom->material != kXVkMaterialSky && geom->material != kXVkMaterialEmissive) { VectorCopy(g_lights.map.emissive_textures[texture_num].emissive, esurf->emissive); } else { - // TODO per-map sky emissive - VectorSet(esurf->emissive, 1000.f, 1000.f, 1000.f); + // TODO see #227 + VectorSet(esurf->emissive, 0.f, 0.f, 0.f); } Matrix3x4_Copy(esurf->transform, *transform_row); diff --git a/ref_vk/vk_ray_model.c b/ref_vk/vk_ray_model.c index 5667d08e..9cb58e7e 100644 --- a/ref_vk/vk_ray_model.c +++ b/ref_vk/vk_ray_model.c @@ -217,6 +217,12 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) { kusochki[i].index_offset = mg->index_offset; kusochki[i].triangles = prim_count; + if (mg->material == kXVkMaterialSky) { + kusochki[i].tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX; + } else { + kusochki[i].tex_base_color &= (~KUSOK_MATERIAL_FLAG_SKYBOX); + } + //kusochki[i].texture = mg->texture; //kusochki[i].roughness = mg->material == kXVkMaterialWater ? 0. : 1.; // FIXME VectorSet(kusochki[i].emissive, 0, 0, 0 ); @@ -379,6 +385,10 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render kusok->tex_roughness = tglob.grayTexture; } + if (geom->material == kXVkMaterialSky) { + kusok->tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX; + } + Vector4Copy(color, kusok->color); XVK_GetEmissiveForTexture( kusok->emissive, geom->texture ); diff --git a/ref_vk/vk_rtx.c b/ref_vk/vk_rtx.c index 70f8d447..0a85d2d0 100644 --- a/ref_vk/vk_rtx.c +++ b/ref_vk/vk_rtx.c @@ -31,6 +31,8 @@ enum { ShaderBindingTable_Hit, ShaderBindingTable_Hit_WithAlphaTest, ShaderBindingTable_Hit_Additive, + ShaderBindingTable_Hit_Shadow, + ShaderBindingTable_Hit__END = ShaderBindingTable_Hit_Shadow, ShaderBindingTable_COUNT }; @@ -353,6 +355,8 @@ static void createPipeline( void ) uint32_t max_visible_surface_lights; float light_grid_cell_size; int max_light_clusters; + uint32_t max_textures; + uint32_t sbt_record_size; } spec_data = { .max_point_lights = MAX_POINT_LIGHTS, .max_emissive_kusochki = MAX_EMISSIVE_KUSOCHKI, @@ -360,6 +364,8 @@ static void createPipeline( void ) .max_visible_surface_lights = MAX_VISIBLE_SURFACE_LIGHTS, .light_grid_cell_size = LIGHT_GRID_CELL_SIZE, .max_light_clusters = MAX_LIGHT_CLUSTERS, + .max_textures = MAX_TEXTURES, + .sbt_record_size = g_rtx.sbt_record_size, }; const VkSpecializationMapEntry spec_map[] = { {.constantID = 0, .offset = offsetof(struct RayShaderSpec, max_point_lights), .size = sizeof(int) }, @@ -368,6 +374,8 @@ static void createPipeline( void ) {.constantID = 3, .offset = offsetof(struct RayShaderSpec, max_visible_surface_lights), .size = sizeof(uint32_t) }, {.constantID = 4, .offset = offsetof(struct RayShaderSpec, light_grid_cell_size), .size = sizeof(float) }, {.constantID = 5, .offset = offsetof(struct RayShaderSpec, max_light_clusters), .size = sizeof(int) }, + {.constantID = 6, .offset = offsetof(struct RayShaderSpec, max_textures), .size = sizeof(uint32_t) }, + {.constantID = 7, .offset = offsetof(struct RayShaderSpec, sbt_record_size), .size = sizeof(uint32_t) }, }; VkSpecializationInfo spec = { @@ -383,6 +391,7 @@ static void createPipeline( void ) ShaderStageIndex_Miss_Shadow, ShaderStageIndex_Miss_Empty, ShaderStageIndex_ClosestHit, + ShaderStageIndex_ClosestHit_Shadow, ShaderStageIndex_AnyHit_AlphaTest, ShaderStageIndex_AnyHit_Additive, ShaderStageIndex_COUNT, @@ -416,6 +425,7 @@ static void createPipeline( void ) DEFINE_SHADER("shadow.rmiss.spv", MISS, ShaderStageIndex_Miss_Shadow); DEFINE_SHADER("empty.rmiss.spv", MISS, ShaderStageIndex_Miss_Empty); DEFINE_SHADER("ray.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit); + DEFINE_SHADER("shadow.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit_Shadow); DEFINE_SHADER("alphamask.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_AlphaTest); DEFINE_SHADER("additive.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_Additive); @@ -429,6 +439,7 @@ static void createPipeline( void ) ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit, SHADER_OFFSET_HIT_REGULAR); ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_WithAlphaTest, SHADER_OFFSET_HIT_ALPHA_TEST); ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Additive, SHADER_OFFSET_HIT_ADDITIVE); + ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Shadow, SHADER_OFFSET_HIT_SHADOW); shader_groups[ShaderBindingTable_RayGen] = (VkRayTracingShaderGroupCreateInfoKHR) { .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, @@ -493,6 +504,15 @@ static void createPipeline( void ) .intersectionShader = VK_SHADER_UNUSED_KHR, }; + shader_groups[ShaderBindingTable_Hit_Shadow] = (VkRayTracingShaderGroupCreateInfoKHR) { + .sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR, + .type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR, + .anyHitShader = VK_SHADER_UNUSED_KHR, + .closestHitShader = ShaderStageIndex_ClosestHit_Shadow, + .generalShader = VK_SHADER_UNUSED_KHR, + .intersectionShader = VK_SHADER_UNUSED_KHR, + }; + XVK_CHECK(vkCreateRayTracingPipelinesKHR(vk_core.device, VK_NULL_HANDLE, g_pipeline_cache, 1, &rtpci, NULL, &g_rtx.pipeline)); ASSERT(g_rtx.pipeline != VK_NULL_HANDLE); @@ -739,7 +759,7 @@ LIST_GBUFFER_IMAGES(GBUFFER_WRITE_BARRIER) } const VkStridedDeviceAddressRegionKHR sbt_raygen = SBT_INDEX(ShaderBindingTable_RayGen, 1); const VkStridedDeviceAddressRegionKHR sbt_miss = SBT_INDEX(ShaderBindingTable_Miss, ShaderBindingTable_Miss_Empty - ShaderBindingTable_Miss); - const VkStridedDeviceAddressRegionKHR sbt_hit = SBT_INDEX(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Additive - ShaderBindingTable_Hit); + const VkStridedDeviceAddressRegionKHR sbt_hit = SBT_INDEX(ShaderBindingTable_Hit, ShaderBindingTable_Hit__END - ShaderBindingTable_Hit); const VkStridedDeviceAddressRegionKHR sbt_callable = { 0 }; vkCmdTraceRaysKHR(cmdbuf, &sbt_raygen, &sbt_miss, &sbt_hit, &sbt_callable, FRAME_WIDTH, FRAME_HEIGHT, 1 ); diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index be29b6db..b5795b60 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -508,7 +508,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, tex->height = layers[0]->height; mipCount = CalcMipmapCount( tex, true); - gEngine.Con_Reportf("Uploading texture %s, mips=%d, layers=%d\n", tex->name, mipCount, layers); + gEngine.Con_Reportf("Uploading texture %s, mips=%d, layers=%d\n", tex->name, mipCount, num_layers); // TODO this vvv // // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides @@ -989,7 +989,7 @@ void XVK_SetupSky( const char *skyboxname ) if( !Common_CheckTexName( loadname )) goto fail; - // needed? VK_ProcessImage( tex, pic ); + Q_strncpy( tglob.skybox_cube.name, loadname, sizeof( tglob.skybox_cube.name )); if (uploadTexture(&tglob.skybox_cube, sides, 6, true)) { tglob.fCustomSkybox = true; gEngine.Con_DPrintf( "done\n" ); From 405a9ecbb4ce2e8183e716175b701cd4b6ea25f7 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Thu, 25 Nov 2021 12:31:36 -0800 Subject: [PATCH 6/9] rtx: skybox srgb workaround for #230 --- ref_vk/shaders/ray.rchit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ref_vk/shaders/ray.rchit b/ref_vk/shaders/ray.rchit index 193dd884..5ae009db 100644 --- a/ref_vk/shaders/ray.rchit +++ b/ref_vk/shaders/ray.rchit @@ -96,7 +96,7 @@ void main() { payload.transmissiveness = 0.; payload.normal = vec3(0.); payload.geometry_normal = vec3(0.); - payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb; + payload.emissive = pow(texture(skybox, gl_WorldRayDirectionEXT).rgb, vec3(2.2)); // Why?! See #230 payload.kusok_index = -1; payload.roughness = 0.; payload.metalness = 0.; From 1624f4620a6cb3ace2c015121052dd2336c447d1 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Thu, 25 Nov 2021 13:51:39 -0800 Subject: [PATCH 7/9] mat: load materials from multiple sources; abs paths - look for materials in: - pbr/materials.mat - pbr/models/materials.mat - pbr/wadname.wad/materials.mat - pbr/maps/mapname.bsp/materials.mat - all paths are relative to their materials.mat, except for ones that begin with '/', which are relative to `pbr` dir pbr dir should be placed in modname dir, e.g. 'valve' #155 --- ref_vk/vk_materials.c | 93 ++++++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/ref_vk/vk_materials.c b/ref_vk/vk_materials.c index f471003d..074ec5e9 100644 --- a/ref_vk/vk_materials.c +++ b/ref_vk/vk_materials.c @@ -33,17 +33,10 @@ static int findTextureNamedLike( const char *texture_name ) { return tex_id ? tex_id : -1; } -static int loadTextureF( const char *fmt, ... ) { - int tex_id = 0; - char buffer[1024]; - va_list argptr; - va_start( argptr, fmt ); - vsnprintf( buffer, sizeof buffer, fmt, argptr ); - va_end( argptr ); - - tex_id = VK_LoadTexture( buffer, NULL, 0, 0); - gEngine.Con_Reportf("Loading texture %s => %d\n", buffer, tex_id); +static int loadTexture( const char *filename ) { + const int tex_id = VK_LoadTexture( filename, NULL, 0, 0); + gEngine.Con_Reportf("Loading texture %s => %d\n", filename, tex_id); return tex_id ? tex_id : -1; } @@ -61,6 +54,8 @@ static void loadMaterialsFromFile( const char *filename ) { }; int current_material_index = -1; + gEngine.Con_Reportf("Loading materials from %s\n", filename); + if ( !data ) return; @@ -104,33 +99,55 @@ static void loadMaterialsFromFile( const char *filename ) { if (Q_stricmp(key, "for") == 0) { current_material_index = findTextureNamedLike(value); - } else if (Q_stricmp(key, "basecolor_map") == 0) { - if ((current_material.base_color = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) { - gEngine.Con_Printf(S_ERROR "Failed to load basecolor_map texture %s\n", value); - } - } else if (Q_stricmp(key, "normal_map") == 0) { - if ((current_material.normalmap = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) { - gEngine.Con_Printf(S_ERROR "Failed to load normal_map texture %s\n", value); - current_material.normalmap = 0; - } - } else if (Q_stricmp(key, "metal_map") == 0) { - if ((current_material.metalness = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) { - gEngine.Con_Printf(S_ERROR "Failed to load metal_map texture %s\n", value); - current_material.metalness = tglob.blackTexture; - } - } else if (Q_stricmp(key, "roughness_map") == 0) { - if ((current_material.roughness = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) { - gEngine.Con_Printf(S_ERROR "Failed to load roughness_map texture %s\n", value); - current_material.roughness = tglob.whiteTexture; - } } else { - gEngine.Con_Printf(S_ERROR "Unknown material key %s\n", key); + char texture_path[256]; + int *tex_id_dest; + int tex_id = loadTexture(texture_path); + if (Q_stricmp(key, "basecolor_map") == 0) { + tex_id_dest = ¤t_material.base_color; + } else if (Q_stricmp(key, "normal_map") == 0) { + tex_id_dest = ¤t_material.normalmap; + } else if (Q_stricmp(key, "metal_map") == 0) { + tex_id_dest = ¤t_material.metalness; + } else if (Q_stricmp(key, "roughness_map") == 0) { + tex_id_dest = ¤t_material.roughness; + } else { + gEngine.Con_Printf(S_ERROR "Unknown material key %s\n", key); + continue; + } + + if (value[0] == '/') { + // Path relative to valve/pbr dir + Q_snprintf(texture_path, sizeof(texture_path), "pbr%s", value); + } else { + // Path relative to current material.mat file + Q_snprintf(texture_path, sizeof(texture_path), "%.*s%s", path_end - path_begin, path_begin, value); + } + + tex_id = loadTexture(texture_path); + if (tex_id < 0) { + gEngine.Con_Printf(S_ERROR "Failed to load texture \"%s\" for key \"%s\"\n", value, key); + continue; + } + + *tex_id_dest = tex_id; } } Mem_Free( data ); } +static void loadMaterialsFromFileF( const char *fmt, ... ) { + char buffer[256]; + va_list argptr; + + va_start( argptr, fmt ); + vsnprintf( buffer, sizeof buffer, fmt, argptr ); + va_end( argptr ); + + loadMaterialsFromFile( buffer ); +} + void XVK_ReloadMaterials( void ) { for (int i = 0; i < MAX_TEXTURES; ++i) { xvk_material_t *const mat = g_materials.materials + i; @@ -149,7 +166,21 @@ void XVK_ReloadMaterials( void ) { } loadMaterialsFromFile( "pbr/materials.mat" ); - // TODO map-specific + loadMaterialsFromFile( "pbr/models/materials.mat" ); + + { + const char *wad = g_map_entities.wadlist; + for (; *wad;) { + const char *const wad_end = Q_strchr(wad, ';'); + loadMaterialsFromFileF("pbr/%.*s/materials.mat", wad_end - wad, wad); + wad = wad_end + 1; + } + } + + { + const model_t *map = gEngine.pfnGetModelByIndex( 1 ); + loadMaterialsFromFileF("pbr/%s/materials.mat", map->name); + } } xvk_material_t* XVK_GetMaterialForTextureIndex( int tex_index ) { From f0aaa3cd10f8aaa0f6f0767e1950e89ae3b2178d Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Thu, 25 Nov 2021 14:38:03 -0800 Subject: [PATCH 8/9] materials: enable force-reloading textures mark such materials as `"force_reload" "1"` --- ref_vk/vk_materials.c | 12 ++++++++---- ref_vk/vk_textures.c | 13 +++++++++++++ ref_vk/vk_textures.h | 2 ++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/ref_vk/vk_materials.c b/ref_vk/vk_materials.c index 074ec5e9..62a4f5c7 100644 --- a/ref_vk/vk_materials.c +++ b/ref_vk/vk_materials.c @@ -34,8 +34,8 @@ static int findTextureNamedLike( const char *texture_name ) { return tex_id ? tex_id : -1; } -static int loadTexture( const char *filename ) { - const int tex_id = VK_LoadTexture( filename, NULL, 0, 0); +static int loadTexture( const char *filename, qboolean force_reload ) { + const int tex_id = force_reload ? XVK_LoadTextureReplace( filename, NULL, 0, 0 ) : VK_LoadTexture( filename, NULL, 0, 0 ); gEngine.Con_Reportf("Loading texture %s => %d\n", filename, tex_id); return tex_id ? tex_id : -1; } @@ -53,6 +53,7 @@ static void loadMaterialsFromFile( const char *filename ) { .normalmap = 0, }; int current_material_index = -1; + qboolean force_reload = false; gEngine.Con_Reportf("Loading materials from %s\n", filename); @@ -80,6 +81,7 @@ static void loadMaterialsFromFile( const char *filename ) { .roughness = tglob.whiteTexture, .normalmap = 0, }; + force_reload = false; continue; } @@ -99,10 +101,12 @@ static void loadMaterialsFromFile( const char *filename ) { if (Q_stricmp(key, "for") == 0) { current_material_index = findTextureNamedLike(value); + } else if (Q_stricmp(key, "force_reload") == 0) { + force_reload = Q_atoi(value) != 0; } else { char texture_path[256]; int *tex_id_dest; - int tex_id = loadTexture(texture_path); + int tex_id = -1; if (Q_stricmp(key, "basecolor_map") == 0) { tex_id_dest = ¤t_material.base_color; } else if (Q_stricmp(key, "normal_map") == 0) { @@ -124,7 +128,7 @@ static void loadMaterialsFromFile( const char *filename ) { Q_snprintf(texture_path, sizeof(texture_path), "%.*s%s", path_end - path_begin, path_begin, value); } - tex_id = loadTexture(texture_path); + tex_id = loadTexture(texture_path, force_reload); if (tex_id < 0) { gEngine.Con_Printf(S_ERROR "Failed to load texture \"%s\" for key \"%s\"\n", value, key); continue; diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index b5795b60..538b093d 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -744,6 +744,19 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags ) return tex - vk_textures; } +int XVK_LoadTextureReplace( const char *name, const byte *buf, size_t size, int flags ) { + vk_texture_t *tex; + if( !Common_CheckTexName( name )) + return 0; + + // free if already loaded + if(( tex = Common_TextureForName( name ))) { + VK_FreeTexture( tex - vk_textures ); + } + + return VK_LoadTexture( name, buf, size, flags ); +} + int VK_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags ) { gEngine.Con_Printf("VK FIXME: %s\n", __FUNCTION__); diff --git a/ref_vk/vk_textures.h b/ref_vk/vk_textures.h index 37d99cf8..ae94c905 100644 --- a/ref_vk/vk_textures.h +++ b/ref_vk/vk_textures.h @@ -66,6 +66,8 @@ int VK_CreateTextureArray( const char *name, int width, int height, int depth, void VK_FreeTexture( unsigned int texnum ); int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ); +int XVK_LoadTextureReplace( const char *name, const byte *buf, size_t size, int flags ); + int XVK_TextureLookupF( const char *fmt, ...); #define VK_LoadTextureInternal( name, pic, flags ) VK_LoadTextureFromBuffer( name, pic, flags, false ) From c2748ff03465e6e42d16b8c68ad6d6db63dbb5de Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Thu, 25 Nov 2021 15:08:16 -0800 Subject: [PATCH 9/9] fix random crashes on map load how about not freeing stuff and then trying to use it? --- ref_vk/vk_textures.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ref_vk/vk_textures.c b/ref_vk/vk_textures.c index 538b093d..470ff4c2 100644 --- a/ref_vk/vk_textures.c +++ b/ref_vk/vk_textures.c @@ -943,6 +943,7 @@ void XVK_SetupSky( const char *skyboxname ) char sidename[MAX_STRING]; int i, result, len; rgbdata_t *sides[6]; + qboolean success = false; if( !COM_CheckString( skyboxname )) { @@ -993,23 +994,25 @@ void XVK_SetupSky( const char *skyboxname ) gEngine.Con_DPrintf( "%s%s%s", skyboxname, g_skybox_info[i].suffix, i != 5 ? ", " : ". " ); } + if( i != 6 ) + goto cleanup; + + if( !Common_CheckTexName( loadname )) + goto cleanup; + + Q_strncpy( tglob.skybox_cube.name, loadname, sizeof( tglob.skybox_cube.name )); + success = uploadTexture(&tglob.skybox_cube, sides, 6, true); + +cleanup: for (int j = 0; j < i; ++j) gEngine.FS_FreeImage( sides[j] ); // release source texture - if( i != 6 ) - goto fail; - - if( !Common_CheckTexName( loadname )) - goto fail; - - Q_strncpy( tglob.skybox_cube.name, loadname, sizeof( tglob.skybox_cube.name )); - if (uploadTexture(&tglob.skybox_cube, sides, 6, true)) { + if (success) { tglob.fCustomSkybox = true; gEngine.Con_DPrintf( "done\n" ); - return; // loaded + } else { + tglob.skybox_cube.name[0] = '\0'; + gEngine.Con_DPrintf( "^2failed\n" ); + unloadSkybox(); } - -fail: - gEngine.Con_DPrintf( "^2failed\n" ); - unloadSkybox(); }