Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skybox improvements (E346-E347) #708

Merged
merged 9 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 47 additions & 11 deletions engine/common/imagelib/img_ktx2.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,22 @@ static void Image_KTX2Format( uint32_t ktx2_format )
}
}

static const int g_remap_cube_layer[6] = {
/* Face order
0 1 2 3 4 5 -- index
ft, bk, up, dn, rt, lf -- xash
+x, -x, +y, -y, +z, -z -- KTX2
rt, lf, bk, ft, up, dn -- ref_vk

texture[face] = ktx2[map[face]], e.g.:
texture[rt] = ktx2[+z = 4]
texture[lf] = ktx2[-z = 5]
texture[bk] = ktx2[-x = 1]
...
*/
4, 5, 1, 0, 2, 3
};

static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer, fs_offset_t filesize )
{
ktx2_index_t index;
Expand Down Expand Up @@ -93,7 +109,7 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
return false;
}

if( header->faceCount > 1 )
if( header->faceCount != 1 && header->faceCount != 6 )
{
Con_DPrintf( S_ERROR "%s: unsupported KTX2 faceCount %d\n", __FUNCTION__, header->faceCount );
return false;
Expand Down Expand Up @@ -128,32 +144,52 @@ static qboolean Image_KTX2Parse( const ktx2_header_t *header, const byte *buffer
ktx2_level_t level;
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));

if( mip_size != level.byteLength )
if( mip_size * header->faceCount != level.byteLength )
{
Con_DPrintf( S_ERROR "%s: mip=%d size mismatch read=%d, but computed=%d\n",
__FUNCTION__, mip, (int)level.byteLength, mip_size );
Con_DPrintf( S_ERROR "%s: mip=%d size mismatch read=%d, but computed=%d(mip=%d * faces=%d)\n",
__FUNCTION__, mip, (int)level.byteLength, mip_size * header->faceCount, mip_size, header->faceCount );
return false;
}

total_size += level.byteLength;
max_offset = Q_max( max_offset, level.byteLength + level.byteOffset );
}

if( max_offset > filesize )
if( max_offset > filesize ) {
Con_DPrintf( S_ERROR "%s: size to read %d exceeds file size %d\n",
__FUNCTION__, (int)max_offset, (int)filesize );
return false;
}

image.size = total_size;
image.num_mips = header->levelCount;

image.rgba = Mem_Malloc( host.imagepool, image.size );
memcpy( image.rgba, buffer, image.size );

for( int mip = 0, cursor = 0; mip < header->levelCount; ++mip )
{
ktx2_level_t level;
memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));
memcpy( image.rgba + cursor, buffer + level.byteOffset, level.byteLength );
cursor += level.byteLength;
int cursors[6] = {0};
if ( header->faceCount == 6 ) {
image.flags |= IMAGE_CUBEMAP;

for ( int face = 0; face < header->faceCount; ++face )
cursors[face] = g_remap_cube_layer[face] * total_size / header->faceCount;
}

for( int mip = 0; mip < header->levelCount; ++mip )
{
ktx2_level_t level;
int face_size = 0;

memcpy( &level, levels_begin + mip * sizeof( level ), sizeof( level ));
face_size = level.byteLength / header->faceCount;

for ( int face = 0; face < header->faceCount; ++face )
{
memcpy( image.rgba + cursors[face], buffer + level.byteOffset + face * face_size, face_size );
cursors[face] += face_size;
}
}
}

return true;
Expand All @@ -179,7 +215,7 @@ qboolean Image_LoadKTX2( const char *name, const byte *buffer, fs_offset_t files
image.depth = Q_max( 1, header.pixelDepth );
image.num_mips = 1;

ClearBits( image.flags, IMAGE_HAS_COLOR | IMAGE_HAS_ALPHA | IMAGE_HAS_LUMA );
ClearBits( image.flags, IMAGE_HAS_COLOR | IMAGE_HAS_ALPHA | IMAGE_HAS_LUMA | IMAGE_CUBEMAP );

if( !Image_KTX2Parse( &header, buffer, filesize ))
{
Expand Down
4 changes: 3 additions & 1 deletion engine/common/imagelib/img_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ static qboolean FS_AddSideToPack( int adjust_flags )
}

// keep constant size, render.dll expecting it
image.size = image.source_width * image.source_height * 4;
// NOTE: This is super incorrect for compressed images.
// No idea why it was needed
// image.size = image.source_width * image.source_height * 4;

// mixing dds format with any existing ?
if( image.type != image.source_type )
Expand Down
2 changes: 1 addition & 1 deletion engine/common/imagelib/img_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ static const loadpixformat_t load_null[] =

static const loadpixformat_t load_game[] =
{
{ "%s%s.%s", "ktx2", Image_LoadKTX2, IL_HINT_NO }, // ktx2 for world and studio models
{ "%s%s.%s", "dds", Image_LoadDDS, IL_HINT_NO }, // dds for world and studio models
{ "%s%s.%s", "bmp", Image_LoadBMP, IL_HINT_NO }, // WON menu images
{ "%s%s.%s", "tga", Image_LoadTGA, IL_HINT_NO }, // hl vgui menus
Expand All @@ -105,7 +106,6 @@ static const loadpixformat_t load_game[] =
{ "%s%s.%s", "lmp", Image_LoadLMP, IL_HINT_NO }, // hl menu images (cached.wad etc)
{ "%s%s.%s", "fnt", Image_LoadFNT, IL_HINT_HL }, // hl console font (fonts.wad etc)
{ "%s%s.%s", "pal", Image_LoadPAL, IL_HINT_NO }, // install studio\sprite palette
{ "%s%s.%s", "ktx2", Image_LoadKTX2, IL_HINT_NO }, // ktx2 for world and studio models
{ NULL, NULL, NULL, IL_HINT_NO }
};

Expand Down
68 changes: 68 additions & 0 deletions ref/vk/NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -1011,3 +1011,71 @@ 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)

# 2023-12-14 E347
## TIL engine imagelib `FS_LoadImage()`:
1. Pick format based on extension
2. If no extension is specified, try all supported extensions in sequence.
3. If loading single file failed, try to load it as skybox cubemap:
Go through all sides suffixes and try to load them in the similar fashion:
if no extension, then try all supported extensions

- `Image_Process()` can only rotate uncompressed formats. (Technically it might be possible to also
rotate some compressed format, which will amount to just reordering blocks, and then reordering block
contents. Mendokusai). Therefore, we can't just replace png sides with compressed ktx2 sides directly.
KTX2 sides should be pre-rotated.

# 2023-12-15 E348
## Textures layout
imagelib image buffer layout:
- sides[1|6]
- mips[biggest -> smallest]
- (pixel data)

KTX2 file layout:
- mips[smallest -> biggest]
- sides[1|6]
- (pixel data)

# 2023-12-18 E349
## Xash vs KTX2/vk cubemap face order
Vulkan order:
+X, -X, +Y, -Y, +Z, -Z
rt, lf, bk, ft, up, dn
0, 1, 2, 3, 4, 5

Xash order:
ft, bk, up, dn, rt, lf

Remap (KTX2 -> xash || xash[face] = KTX2[map[face]]):
3, 2, 4, 5, 0, 1

Remap (xash -> vk, vk[map[face]] = xash[face]):
4, 5, 1, 0, 2, 3
??? this shoudln't work

default cubemap order:
xash vk (remapped)
+Y = -X
+X = +Z
+Z = +Y
30 changes: 27 additions & 3 deletions ref/vk/TODO.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
# 2023-12-18 E349
- [x] KTX2 cubemaps
- [ ] improve logs "vk/tex: Loaded skybox pbr/env/%.*s"
- [ ] variable cubemap exposure
- [ ] add skybox test

# 2023-12-15 E348
- [x] fix ktx2 sides corruption

# 2023-12-14 E346-E347
- [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 sides
→ doesn't work as easily, as there's no way to rotate compressed images.
KTX2 sides should be pre-rotated
- [x] do not generate mips for skybox
- [x] support imagelib cubemaps
- [x] use imagelib skybox loader
- [x] Hide all SURF_DRAWSKY while retaining skybox, #579
- [x] possible issues with TF_NOMIPMAP
- [x] used incorrectly when loading blue noise textures
- [x] what about regular usage?

# 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
Expand All @@ -17,7 +42,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.
Expand Down
15 changes: 8 additions & 7 deletions ref/vk/data/valve/luchiki/maps/c2a5.patch
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"_xvk_ent_id" "246" // DANGER sign
"origin" "1 0 0"
}
{
"_xvk_smoothing_threshold" "54" // FIXME
}
{
"_xvk_ent_id" "246" // DANGER sign
"origin" "1 0 0"
}
{
"_xvk_smoothing_threshold" "54" // FIXME
"_xvk_remove_all_sky_surfaces" "1"
}
19 changes: 3 additions & 16 deletions ref/vk/r_speeds.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "vk_framectl.h"
#include "vk_cvar.h"
#include "vk_combuf.h"
#include "stringview.h"

#include "profiler.h"

Expand Down Expand Up @@ -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;
}

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

Expand Down
Loading