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:
Ivan Avdeev 2023-12-14 10:33:26 -05:00
parent f3f14ac968
commit 3cbc11a8f0
16 changed files with 271 additions and 129 deletions

View File

@ -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)

View File

@ -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.

View File

@ -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;
}

View File

@ -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/<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
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/<sky>_<side>.{png, ...} sides
if (skyboxLoadSides(basename, "pbr/env/%.*s"))
goto success;
// 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

View File

@ -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 );

41
ref/vk/stringview.c Normal file
View File

@ -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';
}

13
ref/vk/stringview.h Normal file
View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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(),
},

View File

@ -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 );

View File

@ -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();
}

View File

@ -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

View File

@ -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);