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.
This commit is contained in:
parent
f3f14ac968
commit
3cbc11a8f0
|
@ -1011,3 +1011,23 @@ This would need the same as above, plus:
|
||||||
- A: probably should still do it on GPU lol
|
- 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.
|
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)
|
||||||
|
|
|
@ -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
|
# 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.
|
- [ ] Patch overlay textures (#696) → turned out to be much more difficult than expected.
|
||||||
- [x] Do not patch sprite textures for traditional raster, #695
|
- [x] Do not patch sprite textures for traditional raster, #695
|
||||||
- [x] fixup skybox glitches caused by #666 fix
|
|
||||||
|
|
||||||
# 2023-12-05 E342
|
# 2023-12-05 E342
|
||||||
- [x] tone down the specular indirect blur
|
- [x] tone down the specular indirect blur
|
||||||
|
@ -17,7 +26,6 @@ Longer-term agenda for current season:
|
||||||
- [ ] Tools:
|
- [ ] Tools:
|
||||||
- [ ] Shader profiling. Measure impact of changes. Regressions.
|
- [ ] Shader profiling. Measure impact of changes. Regressions.
|
||||||
- [ ] Better PBR math, e.g.:
|
- [ ] Better PBR math, e.g.:
|
||||||
- [ ] fix black dielectrics, #666
|
|
||||||
- [ ] Transparency:
|
- [ ] Transparency:
|
||||||
- [ ] Figure out why additive transparency differs visibly from raster
|
- [ ] Figure out why additive transparency differs visibly from raster
|
||||||
- [ ] Extract and specialize effects, e.g.
|
- [ ] Extract and specialize effects, e.g.
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "vk_framectl.h"
|
#include "vk_framectl.h"
|
||||||
#include "vk_cvar.h"
|
#include "vk_cvar.h"
|
||||||
#include "vk_combuf.h"
|
#include "vk_combuf.h"
|
||||||
|
#include "stringview.h"
|
||||||
|
|
||||||
#include "profiler.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) {
|
static int findMetricIndexByName( const_string_view_t name) {
|
||||||
for (int i = 0; i < g_speeds.metrics_count; ++i) {
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,7 +314,7 @@ static int findMetricIndexByName( const_string_view_t name) {
|
||||||
|
|
||||||
static int findGraphIndexByName( const_string_view_t name) {
|
static int findGraphIndexByName( const_string_view_t name) {
|
||||||
for (int i = 0; i < g_speeds.graphs_count; ++i) {
|
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;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "r_speeds.h"
|
#include "r_speeds.h"
|
||||||
#include "profiler.h"
|
#include "profiler.h"
|
||||||
#include "unordered_roadmap.h"
|
#include "unordered_roadmap.h"
|
||||||
|
#include "stringview.h"
|
||||||
|
|
||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
#include "crtlib.h"
|
#include "crtlib.h"
|
||||||
|
@ -28,10 +29,9 @@ static struct {
|
||||||
|
|
||||||
vk_texture_t all[MAX_TEXTURES];
|
vk_texture_t all[MAX_TEXTURES];
|
||||||
urmom_desc_t all_desc;
|
urmom_desc_t all_desc;
|
||||||
} g_textures;
|
|
||||||
|
|
||||||
// FIXME imported from vk_textures.h
|
char current_skybox_name[MAX_STRING];
|
||||||
void unloadSkybox( void );
|
} g_textures;
|
||||||
|
|
||||||
static void createDefaultTextures( void );
|
static void createDefaultTextures( void );
|
||||||
static void destroyDefaultTextures( void );
|
static void destroyDefaultTextures( void );
|
||||||
|
@ -287,7 +287,7 @@ static void createDefaultTextures( void )
|
||||||
rgbdata_t *sides[6];
|
rgbdata_t *sides[6];
|
||||||
pic = Common_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR );
|
pic = Common_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR );
|
||||||
for( x = 0; x < 16; x++ )
|
for( x = 0; x < 16; x++ )
|
||||||
((uint *)pic->buffer)[x] = 0xFFFFFFFF;
|
((uint *)pic->buffer)[x] = 0;
|
||||||
|
|
||||||
sides[0] = pic;
|
sides[0] = pic;
|
||||||
sides[1] = pic;
|
sides[1] = pic;
|
||||||
|
@ -296,7 +296,8 @@ static void createDefaultTextures( void )
|
||||||
sides[4] = pic;
|
sides[4] = pic;
|
||||||
sides[5] = 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;
|
return insert.index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static const struct {
|
||||||
const char *suffix;
|
const char *suffix;
|
||||||
uint flags;
|
uint flags;
|
||||||
} g_skybox_info[6] = {
|
} k_skybox_info[6] = {
|
||||||
{"rt", IMAGE_ROT_90},
|
{"rt", IMAGE_ROT_90},
|
||||||
{"lf", IMAGE_FLIP_Y | IMAGE_ROT_90 | IMAGE_FLIP_X},
|
{"lf", IMAGE_FLIP_Y | IMAGE_ROT_90 | IMAGE_FLIP_X},
|
||||||
{"bk", IMAGE_FLIP_Y},
|
{"bk", IMAGE_FLIP_Y},
|
||||||
|
@ -824,7 +825,7 @@ static struct {
|
||||||
#define SKYBOX_HLSTYLE 1
|
#define SKYBOX_HLSTYLE 1
|
||||||
#define SKYBOX_Q1STYLE 2
|
#define SKYBOX_Q1STYLE 2
|
||||||
|
|
||||||
static int CheckSkybox( const char *name )
|
static int CheckSkyboxSides( const char *name )
|
||||||
{
|
{
|
||||||
const char *skybox_ext[] = { "png", "dds", "tga", "bmp" };
|
const char *skybox_ext[] = { "png", "dds", "tga", "bmp" };
|
||||||
int i, j, num_checked_sides;
|
int i, j, num_checked_sides;
|
||||||
|
@ -837,10 +838,9 @@ static int CheckSkybox( const char *name )
|
||||||
for( j = 0; j < 6; j++ )
|
for( j = 0; j < 6; j++ )
|
||||||
{
|
{
|
||||||
// build side name
|
// 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 ))
|
if( gEngine.fsapi->FileExists( sidename, false ))
|
||||||
num_checked_sides++;
|
num_checked_sides++;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( num_checked_sides == 6 )
|
if( num_checked_sides == 6 )
|
||||||
|
@ -849,7 +849,7 @@ static int CheckSkybox( const char *name )
|
||||||
for( j = 0; j < 6; j++ )
|
for( j = 0; j < 6; j++ )
|
||||||
{
|
{
|
||||||
// build side name
|
// 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 ))
|
if( gEngine.fsapi->FileExists( sidename, false ))
|
||||||
num_checked_sides++;
|
num_checked_sides++;
|
||||||
}
|
}
|
||||||
|
@ -861,91 +861,150 @@ static int CheckSkybox( const char *name )
|
||||||
return SKYBOX_MISSED;
|
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];
|
rgbdata_t *sides[6];
|
||||||
qboolean success = false;
|
qboolean success = false;
|
||||||
int i;
|
|
||||||
|
|
||||||
// release old skybox
|
|
||||||
unloadSkybox();
|
|
||||||
DEBUG( "SKY: " );
|
|
||||||
|
|
||||||
for( i = 0; i < 6; i++ ) {
|
for( i = 0; i < 6; i++ ) {
|
||||||
char sidename[MAX_STRING];
|
char sidename[MAX_STRING];
|
||||||
if( style == SKYBOX_HLSTYLE )
|
if( style == SKYBOX_HLSTYLE )
|
||||||
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, g_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);
|
sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0);
|
||||||
if (!sides[i] || !sides[i]->buffer)
|
if (!sides[i] || !sides[i]->buffer)
|
||||||
break;
|
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
|
// we need to expand image into RGBA buffer
|
||||||
if( sides[i]->type == PF_INDEXED_24 || sides[i]->type == PF_INDEXED_32 )
|
if( sides[i]->type == PF_INDEXED_24 || sides[i]->type == PF_INDEXED_32 )
|
||||||
img_flags |= IMAGE_FORCE_RGBA;
|
img_flags |= IMAGE_FORCE_RGBA;
|
||||||
gEngine.Image_Process( &sides[i], 0, 0, img_flags, 0.f );
|
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 )
|
if( i != 6 )
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
if( !checkTextureName( prefix ))
|
{
|
||||||
goto cleanup;
|
const qboolean is_placeholder = false;
|
||||||
|
success = R_VkTexturesSkyboxUpload( prefix, sides, kColorspaceGamma, is_placeholder );
|
||||||
success = R_VkTexturesSkyboxUpload( prefix, sides, kColorspaceGamma, false );
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
for (int j = 0; j < i; ++j)
|
for (int j = 0; j < i; ++j)
|
||||||
gEngine.FS_FreeImage( sides[j] ); // release source texture
|
gEngine.FS_FreeImage( sides[j] ); // release source texture
|
||||||
|
|
||||||
if (success) {
|
if (success)
|
||||||
tglob.fCustomSkybox = true;
|
DEBUG( "Loaded sided skybox %s", prefix );
|
||||||
DEBUG( "Skybox done" );
|
|
||||||
} else {
|
|
||||||
ERR( "Skybox failed" );
|
|
||||||
unloadSkybox();
|
|
||||||
}
|
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *skybox_default = "desert";
|
static void makeSkyboxPath(const char *skyboxname, const char *skybox_prefix, char *out_name, int out_length ) {
|
||||||
static const char *skybox_prefixes[] = { "pbr/env/%s", "gfx/env/%s" };
|
Q_snprintf( out_name, out_length, skybox_prefix, skyboxname );
|
||||||
|
COM_StripExtension( out_name );
|
||||||
|
|
||||||
void R_TextureSetupSky( const char *skyboxname ) {
|
// kill the underline suffix to find them manually later
|
||||||
if( !COM_CheckString( skyboxname ))
|
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();
|
skyboxUnload();
|
||||||
return; // clear old skybox
|
return true; // clear old skybox
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYSIZE(skybox_prefixes); ++i) {
|
// Do not reload the same skybox
|
||||||
char loadname[MAX_STRING];
|
// TODO except explicit patches reload
|
||||||
int style, len;
|
if (!force_reload && svCmp(basename, g_textures.current_skybox_name) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
Q_snprintf( loadname, sizeof( loadname ), skybox_prefixes[i], skyboxname );
|
// Try loading skybox in this sequence:
|
||||||
COM_StripExtension( loadname );
|
// 1. Single pbr/env/<sky>.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
|
if (R_VkTexturesSkyboxUploadKTX(ktx_path))
|
||||||
len = Q_strlen( loadname );
|
goto success;
|
||||||
|
|
||||||
if( loadname[len - 1] == '_' )
|
|
||||||
loadname[len - 1] = '\0';
|
|
||||||
style = CheckSkybox( loadname );
|
|
||||||
|
|
||||||
if (loadSkybox(loadname, style))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try default skybox if failed
|
// 2. pbr/env/<sky>_<side>.{png, ...} sides
|
||||||
if (Q_stricmp(skyboxname, skybox_default) != 0) {
|
if (skyboxLoadSides(basename, "pbr/env/%.*s"))
|
||||||
WARN("missed or incomplete skybox '%s', trying default '%s'", skyboxname, skybox_default);
|
goto success;
|
||||||
R_TextureSetupSky( skybox_default );
|
|
||||||
|
// 3. Old gfx/env/<sky>_<side>.{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
|
// FIXME move to r_textures_extra.h
|
||||||
|
|
|
@ -23,6 +23,8 @@ typedef struct vk_textures_global_s
|
||||||
|
|
||||||
// TODO wire it up for ref_interface_t return
|
// TODO wire it up for ref_interface_t return
|
||||||
qboolean fCustomSkybox;
|
qboolean fCustomSkybox;
|
||||||
|
|
||||||
|
qboolean current_map_has_surf_sky;
|
||||||
} vk_textures_global_t;
|
} vk_textures_global_t;
|
||||||
|
|
||||||
// TODO rename this consistently
|
// TODO rename this consistently
|
||||||
|
@ -37,7 +39,7 @@ void R_TexturesShutdown( void );
|
||||||
int R_TextureFindByName( const char *name );
|
int R_TextureFindByName( const char *name );
|
||||||
const char* R_TextureGetNameByIndex( unsigned int texnum );
|
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_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 );
|
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;
|
||||||
struct vk_texture_s *R_TextureGetByIndex( uint index );
|
struct vk_texture_s *R_TextureGetByIndex( uint index );
|
||||||
|
|
||||||
|
void R_TextureSetupSky( const char *skyboxname, qboolean force_reload );
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include "stringview.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
|
@ -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);
|
|
@ -83,6 +83,7 @@ typedef struct {
|
||||||
int animated_count;
|
int animated_count;
|
||||||
int conveyors_count;
|
int conveyors_count;
|
||||||
int conveyors_vertices_count;
|
int conveyors_vertices_count;
|
||||||
|
int sky_surfaces_count;
|
||||||
|
|
||||||
water_model_sizes_t water, side_water;
|
water_model_sizes_t water, side_water;
|
||||||
} model_sizes_t;
|
} model_sizes_t;
|
||||||
|
@ -992,8 +993,10 @@ static model_sizes_t computeSizes( const model_t *mod, qboolean is_worldmodel )
|
||||||
sizes.conveyors_count++;
|
sizes.conveyors_count++;
|
||||||
sizes.conveyors_vertices_count += surf->numedges;
|
sizes.conveyors_vertices_count += surf->numedges;
|
||||||
break;
|
break;
|
||||||
case BrushSurface_Regular:
|
|
||||||
case BrushSurface_Sky:
|
case BrushSurface_Sky:
|
||||||
|
sizes.sky_surfaces_count++;
|
||||||
|
break;
|
||||||
|
case BrushSurface_Regular:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1610,6 +1613,11 @@ qboolean R_BrushModelLoad( model_t *mod, qboolean is_worldmodel ) {
|
||||||
|
|
||||||
const model_sizes_t sizes = computeSizes( mod, 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 (sizes.num_surfaces != 0) {
|
||||||
if (!createRenderModel(mod, bmodel, sizes, is_worldmodel)) {
|
if (!createRenderModel(mod, bmodel, sizes, is_worldmodel)) {
|
||||||
ERR("Could not load brush model %s", mod->name);
|
ERR("Could not load brush model %s", mod->name);
|
||||||
|
|
|
@ -28,12 +28,5 @@ inline static int clampi32(int v, int min, int max) {
|
||||||
return v;
|
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_api_t gEngine;
|
||||||
extern ref_globals_t *gpGlobals;
|
extern ref_globals_t *gpGlobals;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "vk_logs.h"
|
#include "vk_logs.h"
|
||||||
#include "vk_cvar.h"
|
#include "vk_cvar.h"
|
||||||
|
#include "stringview.h"
|
||||||
|
|
||||||
uint32_t g_log_debug_bits = 0;
|
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) {
|
for (int i = 0; i < COUNTOF(g_log_module_pairs); ++i) {
|
||||||
const struct log_pair_t *const pair = 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);
|
gEngine.Con_Reportf("Enabling verbose logs for module \"%.*s\"\n", name.len, name.s);
|
||||||
bit = pair->bit;
|
bit = pair->bit;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -559,7 +559,7 @@ static const ref_interface_t gReffuncs =
|
||||||
.R_GetTextureOriginalBuffer = R_GetTextureOriginalBuffer_UNUSED,
|
.R_GetTextureOriginalBuffer = R_GetTextureOriginalBuffer_UNUSED,
|
||||||
.GL_LoadTextureFromBuffer = R_TextureUploadFromBuffer,
|
.GL_LoadTextureFromBuffer = R_TextureUploadFromBuffer,
|
||||||
.GL_ProcessTexture = GL_ProcessTexture_UNUSED,
|
.GL_ProcessTexture = GL_ProcessTexture_UNUSED,
|
||||||
.R_SetupSky = R_TextureSetupSky,
|
.R_SetupSky = R_TextureSetupCustomSky,
|
||||||
|
|
||||||
// 2D
|
// 2D
|
||||||
R_Set2DMode,
|
R_Set2DMode,
|
||||||
|
|
|
@ -118,13 +118,14 @@ static int findResourceOrEmptySlot(const char *name) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VK_RayNewMap( void ) {
|
void VK_RayNewMapBegin( void ) {
|
||||||
RT_VkAccelNewMap();
|
RT_VkAccelNewMap();
|
||||||
RT_RayModel_Clear();
|
RT_RayModel_Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VK_RayNewMapEnd( void ) {
|
||||||
g_rtx.res[ExternalResource_skybox].resource = (vk_resource_t){
|
g_rtx.res[ExternalResource_skybox].resource = (vk_resource_t){
|
||||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
// FIXME we should pick tglob.dii_all_textures here directly
|
|
||||||
.value = (vk_descriptor_value_t){
|
.value = (vk_descriptor_value_t){
|
||||||
.image = R_VkTexturesGetSkyboxDescriptorImageInfo(),
|
.image = R_VkTexturesGetSkyboxDescriptorImageInfo(),
|
||||||
},
|
},
|
||||||
|
@ -132,7 +133,6 @@ void VK_RayNewMap( void ) {
|
||||||
|
|
||||||
g_rtx.res[ExternalResource_blue_noise_texture].resource = (vk_resource_t){
|
g_rtx.res[ExternalResource_blue_noise_texture].resource = (vk_resource_t){
|
||||||
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
// FIXME we should pick tglob.dii_all_textures here directly
|
|
||||||
.value = (vk_descriptor_value_t){
|
.value = (vk_descriptor_value_t){
|
||||||
.image = R_VkTexturesGetBlueNoiseImageInfo(),
|
.image = R_VkTexturesGetBlueNoiseImageInfo(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,7 +27,8 @@ typedef struct {
|
||||||
} vk_ray_frame_render_args_t;
|
} vk_ray_frame_render_args_t;
|
||||||
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args);
|
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 );
|
qboolean VK_RayInit( void );
|
||||||
void VK_RayShutdown( void );
|
void VK_RayShutdown( void );
|
||||||
|
|
|
@ -87,30 +87,6 @@ static void loadLights( const model_t *const map ) {
|
||||||
RT_LightsLoadEnd();
|
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 ) {
|
static void preloadModels( void ) {
|
||||||
const int num_models = gEngine.EngineGetParm( PARM_NUMMODELS, 0 );
|
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) {
|
static void loadMap(const model_t* const map, qboolean force_reload) {
|
||||||
mapLoadBegin(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_RayNewMapBegin();
|
||||||
|
|
||||||
|
RT_LightsNewMap(map);
|
||||||
|
|
||||||
R_SpriteNewMapFIXME();
|
R_SpriteNewMapFIXME();
|
||||||
|
|
||||||
|
@ -162,8 +152,22 @@ static void loadMap(const model_t* const map) {
|
||||||
|
|
||||||
preloadModels();
|
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);
|
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 ) {
|
static void reloadPatches( void ) {
|
||||||
|
@ -176,7 +180,8 @@ static void reloadPatches( void ) {
|
||||||
R_BrushModelDestroyAll();
|
R_BrushModelDestroyAll();
|
||||||
|
|
||||||
const model_t *const map = gEngine.pfnGetModelByIndex( 1 );
|
const model_t *const map = gEngine.pfnGetModelByIndex( 1 );
|
||||||
loadMap(map);
|
const qboolean force_reload = true;
|
||||||
|
loadMap(map, force_reload);
|
||||||
|
|
||||||
R_VkStagingFlushSync();
|
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
|
// Make sure that we're not rendering anything before starting to mess with GPU objects
|
||||||
XVK_CHECK(vkDeviceWaitIdle(vk_core.device));
|
XVK_CHECK(vkDeviceWaitIdle(vk_core.device));
|
||||||
R_TextureSetupSky( gEngine.pfnGetMoveVars()->skyName );
|
const qboolean force_reload = false;
|
||||||
|
loadMap(map, force_reload);
|
||||||
loadMap(map);
|
|
||||||
|
|
||||||
R_StudioResetPlayerModels();
|
R_StudioResetPlayerModels();
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,9 +58,6 @@ void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, int flags
|
||||||
static VkSampler pickSamplerForFlags( texFlags_t 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);
|
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
|
// Hardcode blue noise texture size to 64x64x64
|
||||||
#define BLUE_NOISE_SIZE 64
|
#define BLUE_NOISE_SIZE 64
|
||||||
#define BLUE_NOISE_NAME_F "bluenoise/LDR_RGBA_%d.png"
|
#define BLUE_NOISE_NAME_F "bluenoise/LDR_RGBA_%d.png"
|
||||||
|
@ -189,7 +186,7 @@ qboolean R_VkTexturesInit( void ) {
|
||||||
static void textureDestroy( unsigned int index );
|
static void textureDestroy( unsigned int index );
|
||||||
|
|
||||||
void R_VkTexturesShutdown( void ) {
|
void R_VkTexturesShutdown( void ) {
|
||||||
unloadSkybox();
|
R_VkTexturesSkyboxUnload();
|
||||||
R_VkTextureDestroy(-1, &g_vktextures.cubemap_placeholder);
|
R_VkTextureDestroy(-1, &g_vktextures.cubemap_placeholder);
|
||||||
R_VkTextureDestroy(-1, &g_vktextures.blue_noise);
|
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;
|
// 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) {
|
if (g_vktextures.skybox_cube.vk.image.image) {
|
||||||
R_VkTextureDestroy( -1, &g_vktextures.skybox_cube );
|
R_VkTextureDestroy( -1, &g_vktextures.skybox_cube );
|
||||||
memset(&g_vktextures.skybox_cube, 0, sizeof(g_vktextures.skybox_cube));
|
memset(&g_vktextures.skybox_cube, 0, sizeof(g_vktextures.skybox_cube));
|
||||||
}
|
}
|
||||||
|
|
||||||
tglob.fCustomSkybox = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDescriptorImageInfo R_VkTexturesGetSkyboxDescriptorImageInfo( void ) {
|
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);
|
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 ) {
|
VkDescriptorSet R_VkTextureGetDescriptorUnorm( uint index ) {
|
||||||
ASSERT( index < MAX_TEXTURES );
|
ASSERT( index < MAX_TEXTURES );
|
||||||
// TODO make an array of unorm descriptors
|
// TODO make an array of unorm descriptors
|
||||||
|
|
|
@ -35,6 +35,8 @@ qboolean R_VkTexturesInit( void );
|
||||||
void R_VkTexturesShutdown( 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_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);
|
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);
|
void R_VkTextureDestroy(int index, vk_texture_t *tex);
|
||||||
|
|
Loading…
Reference in New Issue