From 3cbc11a8f00f9aa67c1a02d147a2b99e22d41a06 Mon Sep 17 00:00:00 2001 From: Ivan Avdeev Date: Thu, 14 Dec 2023 10:33:26 -0500 Subject: [PATCH] vk: rt: optimize hires skybox loading - Do not load skybox at all if there are no SURF_DRAWSKY, #706, #579 - Do not reload the same skybox, #706 Also refactor skybox loading a bit. Prepare for KTX2 skyboxes. --- ref/vk/NOTES.md | 20 +++++ ref/vk/TODO.md | 14 +++- ref/vk/r_speeds.c | 19 +---- ref/vk/r_textures.c | 173 +++++++++++++++++++++++++++++-------------- ref/vk/r_textures.h | 6 +- ref/vk/stringview.c | 41 ++++++++++ ref/vk/stringview.h | 13 ++++ ref/vk/vk_brush.c | 10 ++- ref/vk/vk_common.h | 7 -- ref/vk/vk_logs.c | 3 +- ref/vk/vk_rmain.c | 2 +- ref/vk/vk_rtx.c | 6 +- ref/vk/vk_rtx.h | 3 +- ref/vk/vk_scene.c | 66 +++++++++-------- ref/vk/vk_textures.c | 15 ++-- ref/vk/vk_textures.h | 2 + 16 files changed, 271 insertions(+), 129 deletions(-) create mode 100644 ref/vk/stringview.c create mode 100644 ref/vk/stringview.h diff --git a/ref/vk/NOTES.md b/ref/vk/NOTES.md index 376d3fd8..287e7b79 100644 --- a/ref/vk/NOTES.md +++ b/ref/vk/NOTES.md @@ -1011,3 +1011,23 @@ This would need the same as above, plus: - A: probably should still do it on GPU lol This would also allow passing arbitrary per-pixel data from shaders, which would make shader debugging much much easier. + +# 2023-12-12 E346 +## Skyboxes +### Current state +- `R_TextureSetupSky()` + - called from: + ← `vk_scene.c`/`R_NewMap()` + ← engine ?? -- seems optional, r_soft doesn't implement it. Set on: + - `skybox` console command + - certain movevars change, whatever that is + - `unloadSkybox()` + - for [pbr/, old/] do + - `CheckSkybox()` + - make sidenames and check whether files exist + - `loadSkybox()` + - `unloadSkybox()` + - make sidenames + - `FS_LoadImage()` and `ImageProcess()` + - `R_VkTextureSkyboxUpload(sides)` + - if failed and not default already: `R_TextureSetupSky(default)` (recurse) diff --git a/ref/vk/TODO.md b/ref/vk/TODO.md index dfaaa6b0..f2dd3027 100644 --- a/ref/vk/TODO.md +++ b/ref/vk/TODO.md @@ -1,8 +1,17 @@ +# 2023-12-14 E346 +- [x] Optimize skybox loading, #706 + - [x] Do not load skybox when there are no SURF_DRAWSKY, #579 + - [x] Do not reload the same skybox + - [ ] Load skyboxes from KTX2 + - [ ] do not generate mips for skybox +- [ ] add skybox test + # 2023-12-11 E345 -- [x] fix incorrect basecolor brdf multiplication, #666 +- [x] fix black dielectrics, #666 + - [x] fix incorrect basecolor brdf multiplication, #666 + - [x] fixup skybox glitches caused by #666 fix - [ ] Patch overlay textures (#696) → turned out to be much more difficult than expected. - [x] Do not patch sprite textures for traditional raster, #695 -- [x] fixup skybox glitches caused by #666 fix # 2023-12-05 E342 - [x] tone down the specular indirect blur @@ -17,7 +26,6 @@ Longer-term agenda for current season: - [ ] Tools: - [ ] Shader profiling. Measure impact of changes. Regressions. - [ ] Better PBR math, e.g.: - - [ ] fix black dielectrics, #666 - [ ] Transparency: - [ ] Figure out why additive transparency differs visibly from raster - [ ] Extract and specialize effects, e.g. diff --git a/ref/vk/r_speeds.c b/ref/vk/r_speeds.c index a61a2bac..821c2bfb 100644 --- a/ref/vk/r_speeds.c +++ b/ref/vk/r_speeds.c @@ -3,6 +3,7 @@ #include "vk_framectl.h" #include "vk_cvar.h" #include "vk_combuf.h" +#include "stringview.h" #include "profiler.h" @@ -302,23 +303,9 @@ static void handlePause( uint32_t prev_frame_index ) { } } -// TODO move this to vk_common or something -int stringViewCmp(const_string_view_t sv, const char* s) { - for (int i = 0; i < sv.len; ++i) { - const int d = sv.s[i] - s[i]; - if (d != 0) - return d; - if (s[i] == '\0') - return 1; - } - - // Check that both strings end the same - return '\0' - s[sv.len]; -} - static int findMetricIndexByName( const_string_view_t name) { for (int i = 0; i < g_speeds.metrics_count; ++i) { - if (stringViewCmp(name, g_speeds.metrics[i].name) == 0) + if (svCmp(name, g_speeds.metrics[i].name) == 0) return i; } @@ -327,7 +314,7 @@ static int findMetricIndexByName( const_string_view_t name) { static int findGraphIndexByName( const_string_view_t name) { for (int i = 0; i < g_speeds.graphs_count; ++i) { - if (stringViewCmp(name, g_speeds.graphs[i].name) == 0) + if (svCmp(name, g_speeds.graphs[i].name) == 0) return i; } diff --git a/ref/vk/r_textures.c b/ref/vk/r_textures.c index 19a566f4..45067ca4 100644 --- a/ref/vk/r_textures.c +++ b/ref/vk/r_textures.c @@ -8,6 +8,7 @@ #include "r_speeds.h" #include "profiler.h" #include "unordered_roadmap.h" +#include "stringview.h" #include "xash3d_mathlib.h" #include "crtlib.h" @@ -28,10 +29,9 @@ static struct { vk_texture_t all[MAX_TEXTURES]; urmom_desc_t all_desc; -} g_textures; -// FIXME imported from vk_textures.h -void unloadSkybox( void ); + char current_skybox_name[MAX_STRING]; +} g_textures; static void createDefaultTextures( void ); static void destroyDefaultTextures( void ); @@ -287,7 +287,7 @@ static void createDefaultTextures( void ) rgbdata_t *sides[6]; pic = Common_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR ); for( x = 0; x < 16; x++ ) - ((uint *)pic->buffer)[x] = 0xFFFFFFFF; + ((uint *)pic->buffer)[x] = 0; sides[0] = pic; sides[1] = pic; @@ -296,7 +296,8 @@ static void createDefaultTextures( void ) sides[4] = pic; sides[5] = pic; - R_VkTexturesSkyboxUpload( "skybox_placeholder", sides, kColorspaceGamma, true ); + const qboolean is_placeholder = true; + R_VkTexturesSkyboxUpload( "skybox_placeholder", sides, kColorspaceGamma, is_placeholder ); } } @@ -808,10 +809,10 @@ int R_TextureUploadFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flag return insert.index; } -static struct { +static const struct { const char *suffix; uint flags; -} g_skybox_info[6] = { +} k_skybox_info[6] = { {"rt", IMAGE_ROT_90}, {"lf", IMAGE_FLIP_Y | IMAGE_ROT_90 | IMAGE_FLIP_X}, {"bk", IMAGE_FLIP_Y}, @@ -824,7 +825,7 @@ static struct { #define SKYBOX_HLSTYLE 1 #define SKYBOX_Q1STYLE 2 -static int CheckSkybox( const char *name ) +static int CheckSkyboxSides( const char *name ) { const char *skybox_ext[] = { "png", "dds", "tga", "bmp" }; int i, j, num_checked_sides; @@ -837,10 +838,9 @@ static int CheckSkybox( const char *name ) for( j = 0; j < 6; j++ ) { // build side name - Q_snprintf( sidename, sizeof( sidename ), "%s%s.%s", name, g_skybox_info[j].suffix, skybox_ext[i] ); + Q_snprintf( sidename, sizeof( sidename ), "%s%s.%s", name, k_skybox_info[j].suffix, skybox_ext[i] ); if( gEngine.fsapi->FileExists( sidename, false )) num_checked_sides++; - } if( num_checked_sides == 6 ) @@ -849,7 +849,7 @@ static int CheckSkybox( const char *name ) for( j = 0; j < 6; j++ ) { // build side name - Q_snprintf( sidename, sizeof( sidename ), "%s_%s.%s", name, g_skybox_info[j].suffix, skybox_ext[i] ); + Q_snprintf( sidename, sizeof( sidename ), "%s_%s.%s", name, k_skybox_info[j].suffix, skybox_ext[i] ); if( gEngine.fsapi->FileExists( sidename, false )) num_checked_sides++; } @@ -861,91 +861,150 @@ static int CheckSkybox( const char *name ) return SKYBOX_MISSED; } -static qboolean loadSkybox( const char *prefix, int style ) { +static qboolean loadSkyboxSides( const char *prefix, int style ) { + if( !checkTextureName( prefix )) + return false; + + int i; rgbdata_t *sides[6]; qboolean success = false; - int i; - - // release old skybox - unloadSkybox(); - DEBUG( "SKY: " ); - for( i = 0; i < 6; i++ ) { char sidename[MAX_STRING]; if( style == SKYBOX_HLSTYLE ) - Q_snprintf( sidename, sizeof( sidename ), "%s%s", prefix, g_skybox_info[i].suffix ); - else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", prefix, g_skybox_info[i].suffix ); + Q_snprintf( sidename, sizeof( sidename ), "%s%s", prefix, k_skybox_info[i].suffix ); + else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", prefix, k_skybox_info[i].suffix ); sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0); if (!sides[i] || !sides[i]->buffer) break; { - uint img_flags = g_skybox_info[i].flags; + uint img_flags = k_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 ); } - DEBUG( "%s%s%s", prefix, g_skybox_info[i].suffix, i != 5 ? ", " : ". " ); + DEBUG( "%s%s%s", prefix, k_skybox_info[i].suffix, i != 5 ? ", " : ". " ); } if( i != 6 ) goto cleanup; - if( !checkTextureName( prefix )) - goto cleanup; - - success = R_VkTexturesSkyboxUpload( prefix, sides, kColorspaceGamma, false ); + { + const qboolean is_placeholder = false; + success = R_VkTexturesSkyboxUpload( prefix, sides, kColorspaceGamma, is_placeholder ); + } cleanup: for (int j = 0; j < i; ++j) gEngine.FS_FreeImage( sides[j] ); // release source texture - if (success) { - tglob.fCustomSkybox = true; - DEBUG( "Skybox done" ); - } else { - ERR( "Skybox failed" ); - unloadSkybox(); - } + if (success) + DEBUG( "Loaded sided skybox %s", prefix ); return success; } -static const char *skybox_default = "desert"; -static const char *skybox_prefixes[] = { "pbr/env/%s", "gfx/env/%s" }; +static void makeSkyboxPath(const char *skyboxname, const char *skybox_prefix, char *out_name, int out_length ) { + Q_snprintf( out_name, out_length, skybox_prefix, skyboxname ); + COM_StripExtension( out_name ); -void R_TextureSetupSky( const char *skyboxname ) { - if( !COM_CheckString( skyboxname )) + // kill the underline suffix to find them manually later + const int len = Q_strlen( out_name ); + + if( out_name[len - 1] == '_' ) + out_name[len - 1] = '\0'; +} + +static qboolean skyboxLoadSides(const_string_view_t base, const char *prefix) { + char loadname[MAX_STRING]; + Q_snprintf( loadname, sizeof( loadname ), prefix, base.len, base.s ); + + // TODO merge together as in gl_warp.c + const int style = CheckSkyboxSides( loadname ); + return loadSkyboxSides(loadname, style); +} + +static void skyboxUnload( void ) { + R_VkTexturesSkyboxUnload(); + g_textures.current_skybox_name[0] = '\0'; +} + +static qboolean skyboxTryLoad( const char *skyboxname, qboolean force_reload ) { + // Check whether we even need skybox + if (!tglob.current_map_has_surf_sky) { + DEBUG("No SURF_DRAWSKY surfaces in this map, skipping loading skybox"); + skyboxUnload(); + return true; + } + + const_string_view_t basename = svStripExtension(svFromNullTerminated(skyboxname)); + if (basename.len > 0 && basename.s[basename.len - 1] == '_') + basename.len--; + + if( !basename.len ) { - unloadSkybox(); - return; // clear old skybox + skyboxUnload(); + return true; // clear old skybox } - for (int i = 0; i < ARRAYSIZE(skybox_prefixes); ++i) { - char loadname[MAX_STRING]; - int style, len; + // Do not reload the same skybox + // TODO except explicit patches reload + if (!force_reload && svCmp(basename, g_textures.current_skybox_name) == 0) + return true; - Q_snprintf( loadname, sizeof( loadname ), skybox_prefixes[i], skyboxname ); - COM_StripExtension( loadname ); + // Try loading skybox in this sequence: + // 1. Single pbr/env/.ktx2 cubemap + { + char ktx_path[MAX_STRING]; + Q_snprintf(ktx_path, sizeof(ktx_path), "pbr/env/%.*s.ktx2", basename.len, basename.s); - // kill the underline suffix to find them manually later - len = Q_strlen( loadname ); - - if( loadname[len - 1] == '_' ) - loadname[len - 1] = '\0'; - style = CheckSkybox( loadname ); - - if (loadSkybox(loadname, style)) - return; + if (R_VkTexturesSkyboxUploadKTX(ktx_path)) + goto success; } - // Try default skybox if failed - if (Q_stricmp(skyboxname, skybox_default) != 0) { - WARN("missed or incomplete skybox '%s', trying default '%s'", skyboxname, skybox_default); - R_TextureSetupSky( skybox_default ); + // 2. pbr/env/_.{png, ...} sides + if (skyboxLoadSides(basename, "pbr/env/%.*s")) + goto success; + + // 3. Old gfx/env/_.{png, ...} sides + if (skyboxLoadSides(basename, "gfx/env/%.*s")) + goto success; + + return false; + +success: + svStrncpy(basename, g_textures.current_skybox_name, sizeof(g_textures.current_skybox_name)); + return true; +} + +static const char *k_skybox_default = "desert"; + +void skyboxLoad( const char *skyboxname, qboolean is_custom, qboolean force_reload ) { + DEBUG("%s: skyboxname='%s' is_custom=%d force_reload=%d", __FUNCTION__, skyboxname, is_custom, force_reload); + + if (!skyboxTryLoad(skyboxname, force_reload)) { + WARN("missed or incomplete skybox '%s', trying default '%s'", skyboxname, k_skybox_default); + if (!skyboxTryLoad(k_skybox_default, force_reload)) { + ERR("Failed to load default skybox \"%s\"", k_skybox_default); + } + + return; } + + tglob.fCustomSkybox = is_custom; +} + +void R_TextureSetupCustomSky( const char *skyboxname ) { + const qboolean is_custom = true; + const qboolean force_reload = false; + skyboxLoad(skyboxname, is_custom, force_reload); +} + +void R_TextureSetupSky( const char *skyboxname, qboolean force_reload ) { + const qboolean is_custom = false; + skyboxLoad(skyboxname, is_custom, force_reload); } // FIXME move to r_textures_extra.h diff --git a/ref/vk/r_textures.h b/ref/vk/r_textures.h index 51a4b9b7..12b87fe2 100644 --- a/ref/vk/r_textures.h +++ b/ref/vk/r_textures.h @@ -23,6 +23,8 @@ typedef struct vk_textures_global_s // TODO wire it up for ref_interface_t return qboolean fCustomSkybox; + + qboolean current_map_has_surf_sky; } vk_textures_global_t; // TODO rename this consistently @@ -37,7 +39,7 @@ void R_TexturesShutdown( void ); int R_TextureFindByName( const char *name ); const char* R_TextureGetNameByIndex( unsigned int texnum ); -void R_TextureSetupSky( const char *skyboxname ); +void R_TextureSetupCustomSky( const char *skyboxname ); int R_TextureUploadFromFile( const char *name, const byte *buf, size_t size, int flags ); int R_TextureUploadFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update_only ); @@ -67,3 +69,5 @@ int R_TextureFindByNameLike( const char *texture_name ); struct vk_texture_s; struct vk_texture_s *R_TextureGetByIndex( uint index ); + +void R_TextureSetupSky( const char *skyboxname, qboolean force_reload ); diff --git a/ref/vk/stringview.c b/ref/vk/stringview.c new file mode 100644 index 00000000..75609819 --- /dev/null +++ b/ref/vk/stringview.c @@ -0,0 +1,41 @@ +#include "stringview.h" + +#include + +const_string_view_t svFromNullTerminated( const char *s ) { + return (const_string_view_t){.len = s?strlen(s):0, .s = s}; +} + +int svCmp(const_string_view_t sv, const char* s) { + for (int i = 0; i < sv.len; ++i) { + const int d = sv.s[i] - s[i]; + if (d != 0) + return d; + if (s[i] == '\0') + return 1; + } + + // Check that both strings end the same + return '\0' - s[sv.len]; +} + +const_string_view_t svStripExtension(const_string_view_t sv) { + for (int i = sv.len - 1; i >= 0; --i) { + const char c = sv.s[i]; + if (c == '.') + return (const_string_view_t){ .len = i, .s = sv.s }; + + if (c == '/' || c == '\\' || c == ':') + break; + } + + return sv; +} + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +void svStrncpy(const_string_view_t sv, char *dest, int size) { + const int to_copy = MIN(sv.len, size - 1); + memcpy(dest, sv.s, to_copy); + dest[to_copy] = '\0'; +} diff --git a/ref/vk/stringview.h b/ref/vk/stringview.h new file mode 100644 index 00000000..a704eaaf --- /dev/null +++ b/ref/vk/stringview.h @@ -0,0 +1,13 @@ +#pragma once + +typedef struct { + const char *s; + int len; +} const_string_view_t; + +const_string_view_t svFromNullTerminated( const char *s ); + +int svCmp(const_string_view_t sv, const char* s); +void svStrncpy(const_string_view_t sv, char *dest, int size); + +const_string_view_t svStripExtension(const_string_view_t sv); diff --git a/ref/vk/vk_brush.c b/ref/vk/vk_brush.c index 58581d2c..59a9466e 100644 --- a/ref/vk/vk_brush.c +++ b/ref/vk/vk_brush.c @@ -83,6 +83,7 @@ typedef struct { int animated_count; int conveyors_count; int conveyors_vertices_count; + int sky_surfaces_count; water_model_sizes_t water, side_water; } model_sizes_t; @@ -992,8 +993,10 @@ static model_sizes_t computeSizes( const model_t *mod, qboolean is_worldmodel ) sizes.conveyors_count++; sizes.conveyors_vertices_count += surf->numedges; break; - case BrushSurface_Regular: case BrushSurface_Sky: + sizes.sky_surfaces_count++; + break; + case BrushSurface_Regular: break; } @@ -1610,6 +1613,11 @@ qboolean R_BrushModelLoad( model_t *mod, qboolean is_worldmodel ) { const model_sizes_t sizes = computeSizes( mod, is_worldmodel ); + if (is_worldmodel) { + tglob.current_map_has_surf_sky = sizes.sky_surfaces_count != 0; + DEBUG("sky_surfaces_count=%d, current_map_has_surf_sky=%d", sizes.sky_surfaces_count, tglob.current_map_has_surf_sky); + } + if (sizes.num_surfaces != 0) { if (!createRenderModel(mod, bmodel, sizes, is_worldmodel)) { ERR("Could not load brush model %s", mod->name); diff --git a/ref/vk/vk_common.h b/ref/vk/vk_common.h index ef48438d..eb1156bb 100644 --- a/ref/vk/vk_common.h +++ b/ref/vk/vk_common.h @@ -28,12 +28,5 @@ inline static int clampi32(int v, int min, int max) { return v; } -typedef struct { - const char *s; - int len; -} const_string_view_t; - -int stringViewCmp(const_string_view_t sv, const char* s); - extern ref_api_t gEngine; extern ref_globals_t *gpGlobals; diff --git a/ref/vk/vk_logs.c b/ref/vk/vk_logs.c index 7f3c43c6..f2a8b842 100644 --- a/ref/vk/vk_logs.c +++ b/ref/vk/vk_logs.c @@ -1,5 +1,6 @@ #include "vk_logs.h" #include "vk_cvar.h" +#include "stringview.h" uint32_t g_log_debug_bits = 0; @@ -21,7 +22,7 @@ void R_LogSetVerboseModules( const char *p ) { for (int i = 0; i < COUNTOF(g_log_module_pairs); ++i) { const struct log_pair_t *const pair = g_log_module_pairs + i; - if (stringViewCmp(name, pair->name) == 0) { + if (svCmp(name, pair->name) == 0) { gEngine.Con_Reportf("Enabling verbose logs for module \"%.*s\"\n", name.len, name.s); bit = pair->bit; break; diff --git a/ref/vk/vk_rmain.c b/ref/vk/vk_rmain.c index adb3608b..507c1de5 100644 --- a/ref/vk/vk_rmain.c +++ b/ref/vk/vk_rmain.c @@ -559,7 +559,7 @@ static const ref_interface_t gReffuncs = .R_GetTextureOriginalBuffer = R_GetTextureOriginalBuffer_UNUSED, .GL_LoadTextureFromBuffer = R_TextureUploadFromBuffer, .GL_ProcessTexture = GL_ProcessTexture_UNUSED, - .R_SetupSky = R_TextureSetupSky, + .R_SetupSky = R_TextureSetupCustomSky, // 2D R_Set2DMode, diff --git a/ref/vk/vk_rtx.c b/ref/vk/vk_rtx.c index b1d230a9..418f42b4 100644 --- a/ref/vk/vk_rtx.c +++ b/ref/vk/vk_rtx.c @@ -118,13 +118,14 @@ static int findResourceOrEmptySlot(const char *name) { return -1; } -void VK_RayNewMap( void ) { +void VK_RayNewMapBegin( void ) { RT_VkAccelNewMap(); RT_RayModel_Clear(); +} +void VK_RayNewMapEnd( void ) { g_rtx.res[ExternalResource_skybox].resource = (vk_resource_t){ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - // FIXME we should pick tglob.dii_all_textures here directly .value = (vk_descriptor_value_t){ .image = R_VkTexturesGetSkyboxDescriptorImageInfo(), }, @@ -132,7 +133,6 @@ void VK_RayNewMap( void ) { g_rtx.res[ExternalResource_blue_noise_texture].resource = (vk_resource_t){ .type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, - // FIXME we should pick tglob.dii_all_textures here directly .value = (vk_descriptor_value_t){ .image = R_VkTexturesGetBlueNoiseImageInfo(), }, diff --git a/ref/vk/vk_rtx.h b/ref/vk/vk_rtx.h index d959be76..a009e701 100644 --- a/ref/vk/vk_rtx.h +++ b/ref/vk/vk_rtx.h @@ -27,7 +27,8 @@ typedef struct { } vk_ray_frame_render_args_t; void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args); -void VK_RayNewMap( void ); +void VK_RayNewMapBegin( void ); +void VK_RayNewMapEnd( void ); qboolean VK_RayInit( void ); void VK_RayShutdown( void ); diff --git a/ref/vk/vk_scene.c b/ref/vk/vk_scene.c index 62935d0d..766824c2 100644 --- a/ref/vk/vk_scene.c +++ b/ref/vk/vk_scene.c @@ -87,30 +87,6 @@ static void loadLights( const model_t *const map ) { RT_LightsLoadEnd(); } -// Clears all old map data -static void mapLoadBegin( const model_t *const map ) { - VK_EntityDataClear(); - - // Depends on VK_EntityDataClear() - R_StudioCacheClear(); - R_GeometryBuffer_MapClear(); - - VK_ClearLightmap(); - - // This is to ensure that we have computed lightstyles properly - VK_RunLightStyles(); - - if (vk_core.rtx) - VK_RayNewMap(); - - RT_LightsNewMap(map); -} - -static void mapLoadEnd(const model_t *const map) { - // TODO should we do something like R_BrushEndLoad? - VK_UploadLightmap(); -} - static void preloadModels( void ) { const int num_models = gEngine.EngineGetParm( PARM_NUMMODELS, 0 ); @@ -145,8 +121,22 @@ static void preloadModels( void ) { } } -static void loadMap(const model_t* const map) { - mapLoadBegin(map); +static void loadMap(const model_t* const map, qboolean force_reload) { + VK_EntityDataClear(); + + // Depends on VK_EntityDataClear() + R_StudioCacheClear(); + R_GeometryBuffer_MapClear(); + + VK_ClearLightmap(); + + // This is to ensure that we have computed lightstyles properly + VK_RunLightStyles(); + + if (vk_core.rtx) + VK_RayNewMapBegin(); + + RT_LightsNewMap(map); R_SpriteNewMapFIXME(); @@ -162,8 +152,22 @@ static void loadMap(const model_t* const map) { preloadModels(); + // Can only do after preloadModels(), as we need to know whether there are SURF_DRAWSKY + R_TextureSetupSky( gEngine.pfnGetMoveVars()->skyName, force_reload ); + loadLights(map); - mapLoadEnd(map); + + // TODO should we do something like R_BrushEndLoad? + VK_UploadLightmap(); + + // This is needed mainly for picking up skybox only after it has been loaded + // Most of the things here could be simplified if we had less imperative style for this renderer: + // - Group everything into modules with explicit dependencies, then init/shutdown/newmap order could + // be automatic and correct. + // - "Rendergraph"-like dependencies for resources (like textures, materials, skybox, ...). Then they + // could be loaded lazily when needed, and after all the needed info for them has been collected. + if (vk_core.rtx) + VK_RayNewMapEnd(); } static void reloadPatches( void ) { @@ -176,7 +180,8 @@ static void reloadPatches( void ) { R_BrushModelDestroyAll(); const model_t *const map = gEngine.pfnGetModelByIndex( 1 ); - loadMap(map); + const qboolean force_reload = true; + loadMap(map, force_reload); R_VkStagingFlushSync(); } @@ -260,9 +265,8 @@ void R_NewMap( void ) { // Make sure that we're not rendering anything before starting to mess with GPU objects XVK_CHECK(vkDeviceWaitIdle(vk_core.device)); - R_TextureSetupSky( gEngine.pfnGetMoveVars()->skyName ); - - loadMap(map); + const qboolean force_reload = false; + loadMap(map, force_reload); R_StudioResetPlayerModels(); } diff --git a/ref/vk/vk_textures.c b/ref/vk/vk_textures.c index 5fafc090..8d73226c 100644 --- a/ref/vk/vk_textures.c +++ b/ref/vk/vk_textures.c @@ -58,9 +58,6 @@ void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, int flags static VkSampler pickSamplerForFlags( texFlags_t flags ); static qboolean uploadTexture(int index, vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap, colorspace_hint_e colorspace_hint); -// FIXME should be static -void unloadSkybox( void ); - // Hardcode blue noise texture size to 64x64x64 #define BLUE_NOISE_SIZE 64 #define BLUE_NOISE_NAME_F "bluenoise/LDR_RGBA_%d.png" @@ -189,7 +186,7 @@ qboolean R_VkTexturesInit( void ) { static void textureDestroy( unsigned int index ); void R_VkTexturesShutdown( void ) { - unloadSkybox(); + R_VkTexturesSkyboxUnload(); R_VkTextureDestroy(-1, &g_vktextures.cubemap_placeholder); R_VkTextureDestroy(-1, &g_vktextures.blue_noise); @@ -581,13 +578,12 @@ void R_VkTextureDestroy( int index, vk_texture_t *tex ) { // TODO tex->vk.descriptor_unorm = VK_NULL_HANDLE; } -void unloadSkybox( void ) { +void R_VkTexturesSkyboxUnload(void) { + DEBUG("%s", __FUNCTION__); if (g_vktextures.skybox_cube.vk.image.image) { R_VkTextureDestroy( -1, &g_vktextures.skybox_cube ); memset(&g_vktextures.skybox_cube, 0, sizeof(g_vktextures.skybox_cube)); } - - tglob.fCustomSkybox = false; } VkDescriptorImageInfo R_VkTexturesGetSkyboxDescriptorImageInfo( void ) { @@ -606,6 +602,11 @@ qboolean R_VkTexturesSkyboxUpload( const char *name, rgbdata_t *const sides[6], return uploadTexture(-1, dest, sides, 6, true, colorspace_hint); } +qboolean R_VkTexturesSkyboxUploadKTX( const char *filename ) { + ERR("%s(%s): not implemented", __FUNCTION__, filename); + return false; +} + VkDescriptorSet R_VkTextureGetDescriptorUnorm( uint index ) { ASSERT( index < MAX_TEXTURES ); // TODO make an array of unorm descriptors diff --git a/ref/vk/vk_textures.h b/ref/vk/vk_textures.h index 419f4302..4b5633f7 100644 --- a/ref/vk/vk_textures.h +++ b/ref/vk/vk_textures.h @@ -35,6 +35,8 @@ qboolean R_VkTexturesInit( void ); void R_VkTexturesShutdown( void ); qboolean R_VkTexturesSkyboxUpload( const char *name, rgbdata_t *const sides[6], colorspace_hint_e colorspace_hint, qboolean placeholder); +qboolean R_VkTexturesSkyboxUploadKTX( const char *filename ); +void R_VkTexturesSkyboxUnload(void); qboolean R_VkTextureUpload(int index, vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, colorspace_hint_e colorspace_hint); void R_VkTextureDestroy(int index, vk_texture_t *tex);