vk: move textures to urmom

Known issues:
- pbr materials are completely broken. They end up not being able to
  find textures, seemingly due to memory corruption on materials side,
  not textures.
- There are still places that try to get texture=1
This commit is contained in:
Ivan Avdeev 2023-10-24 14:02:32 -04:00
parent beddef8831
commit 718d6d2592
6 changed files with 231 additions and 189 deletions

View File

@ -7,6 +7,7 @@
#include "vk_logs.h" #include "vk_logs.h"
#include "r_speeds.h" #include "r_speeds.h"
#include "profiler.h" #include "profiler.h"
#include "unordered_roadmap.h"
#define PCG_IMPLEMENT #define PCG_IMPLEMENT
#include "pcg.h" #include "pcg.h"
@ -23,16 +24,13 @@
#define LOG_MODULE LogModule_Textures #define LOG_MODULE LogModule_Textures
#define MODULE_NAME "textures" #define MODULE_NAME "textures"
#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2)
vk_texture_t vk_textures[MAX_TEXTURES];
vk_texture_t* vk_texturesHashTable[TEXTURES_HASH_SIZE];
uint vk_numTextures;
vk_textures_global_t tglob = {0}; vk_textures_global_t tglob = {0};
static struct { static struct {
poolhandle_t mempool; poolhandle_t mempool;
vk_texture_t all[MAX_TEXTURES];
urmom_desc_t all_desc;
} g_textures; } g_textures;
// FIXME imported from vk_textures.h // FIXME imported from vk_textures.h
@ -44,16 +42,18 @@ static int textureLoadFromFileF(int flags, colorspace_hint_e colorspace, const c
qboolean R_TexturesInit( void ) { qboolean R_TexturesInit( void ) {
g_textures.mempool = Mem_AllocPool( "vktextures" ); g_textures.mempool = Mem_AllocPool( "vktextures" );
memset( vk_textures, 0, sizeof( vk_textures )); g_textures.all_desc = (urmom_desc_t){
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable )); .array = g_textures.all,
vk_numTextures = 0; .count = COUNTOF(g_textures.all),
.item_size = sizeof(g_textures.all[0]),
};
// create unused 0-entry urmomInit(&g_textures.all_desc);
Q_strncpy( vk_textures->name, "*unused*", sizeof( vk_textures->name ));
vk_textures->hashValue = COM_HashKey( vk_textures->name, TEXTURES_HASH_SIZE ); // Mark index 0 as occupied to have a special "no texture" value
vk_textures->nextHash = vk_texturesHashTable[vk_textures->hashValue]; g_textures.all[0].hdr_.hash = 0x7fffffff;
vk_texturesHashTable[vk_textures->hashValue] = vk_textures; g_textures.all[0].hdr_.state = 1;
vk_numTextures = 1; Q_strncpy( g_textures.all[0].hdr_.key, "*unused*", sizeof(g_textures.all[0].hdr_.key));
createDefaultTextures(); createDefaultTextures();
@ -65,17 +65,13 @@ qboolean R_TexturesInit( void ) {
void R_TexturesShutdown( void ) void R_TexturesShutdown( void )
{ {
for( unsigned int i = 0; i < vk_numTextures; i++ ) for( int i = 0; i < COUNTOF(g_textures.all); i++ )
R_TextureFree( i ); R_TextureFree( i );
R_VkTexturesShutdown(); R_VkTexturesShutdown();
//memset( tglob.lightmapTextures, 0, sizeof( tglob.lightmapTextures ));
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
memset( vk_textures, 0, sizeof( vk_textures ));
vk_numTextures = 0;
} }
/* OBSOLETE
static vk_texture_t *Common_AllocTexture( const char *name, texFlags_t flags ) static vk_texture_t *Common_AllocTexture( const char *name, texFlags_t flags )
{ {
vk_texture_t *tex; vk_texture_t *tex;
@ -109,25 +105,6 @@ static vk_texture_t *Common_AllocTexture( const char *name, texFlags_t flags )
return tex; return tex;
} }
/* FIXME static */ qboolean Common_CheckTexName( const char *name )
{
int len;
if( !COM_CheckString( name ))
return false;
len = Q_strlen( name );
// because multi-layered textures can exceed name string
if( len >= sizeof( vk_textures->name ))
{
ERR("LoadTexture: too long name %s (%d)", name, len );
return false;
}
return true;
}
static vk_texture_t *Common_TextureForName( const char *name ) static vk_texture_t *Common_TextureForName( const char *name )
{ {
vk_texture_t *tex; vk_texture_t *tex;
@ -144,6 +121,26 @@ static vk_texture_t *Common_TextureForName( const char *name )
return NULL; return NULL;
} }
*/
static qboolean checkTextureName( const char *name )
{
int len;
if( !COM_CheckString( name ))
return false;
len = Q_strlen( name );
// because multi-layered textures can exceed name string
if( len >= sizeof( g_textures.all[0].hdr_.key ))
{
ERR("LoadTexture: too long name %s (%d)", name, len );
return false;
}
return true;
}
static rgbdata_t *Common_FakeImage( int width, int height, int depth, int flags ) static rgbdata_t *Common_FakeImage( int width, int height, int depth, int flags )
{ {
@ -311,7 +308,7 @@ static void createDefaultTextures( void )
R_VkTexturesSkyboxUpload( "skybox_placeholder", sides, kColorspaceGamma, true ); R_VkTexturesSkyboxUpload( "skybox_placeholder", sides, kColorspaceGamma, true );
} }
loadBlueNoiseTextures(); // FIXME convert to 3d texture loadBlueNoiseTextures();
} }
@ -577,31 +574,35 @@ int R_TextureFindByName( const char *name )
{ {
vk_texture_t *tex; vk_texture_t *tex;
if( !Common_CheckTexName( name )) if( !checkTextureName( name ))
return 0; return 0;
// see if already loaded const int index = urmomFind(&g_textures.all_desc, name);
if(( tex = Common_TextureForName( name ))) return index ? index > 0 : 0;
return (tex - vk_textures);
return 0;
} }
const char* R_TextureGetNameByIndex( unsigned int texnum ) const char* R_TextureGetNameByIndex( unsigned int texnum )
{ {
ASSERT( texnum >= 0 && texnum < MAX_TEXTURES ); ASSERT( texnum >= 0 && texnum < MAX_TEXTURES );
return vk_textures[texnum].name; return g_textures.all[texnum].hdr_.key;
} }
static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint, qboolean force_update ) { static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint, qboolean force_update ) {
if( !Common_CheckTexName( name )) if( !checkTextureName( name ))
return 0; return 0;
const urmom_insert_t insert = urmomInsert(&g_textures.all_desc, name);
if (insert.index < 0)
ERR("Cannot allocate texture slot for \"%s\"", name);
ASSERT(insert.index < COUNTOF(g_textures.all));
vk_texture_t *const tex = g_textures.all + insert.index;
// see if already loaded // see if already loaded
vk_texture_t * tex = Common_TextureForName( name ); if (!insert.created && !force_update) {
if( tex && !force_update ) { DEBUG("Found existing texture %s(%d) refcount=%d",
DEBUG("Found existing texture %s(%d) refcount=%d", tex->name, (int)(tex-vk_textures), tex->refcount); TEX_NAME(tex), insert.index, tex->refcount);
return (tex - vk_textures); return insert.index;
} }
uint picFlags = 0; uint picFlags = 0;
@ -616,33 +617,37 @@ static int loadTextureInternal( const char *name, const byte *buf, size_t size,
gEngine.Image_SetForceFlags( picFlags ); gEngine.Image_SetForceFlags( picFlags );
rgbdata_t *const pic = gEngine.FS_LoadImage( name, buf, size ); rgbdata_t *const pic = gEngine.FS_LoadImage( name, buf, size );
if( !pic ) return 0; // couldn't loading image if( !pic ) {
if (insert.created)
urmomRemoveByIndex(&g_textures.all_desc, insert.index);
return 0; // couldn't loading image
}
// allocate the new one if needed tex->flags = flags;
if (!tex)
tex = Common_AllocTexture( name, flags );
else
tex->flags = flags;
// upload texture // upload texture
VK_ProcessImage( tex, pic ); VK_ProcessImage( tex, pic );
const int index = (tex - vk_textures); if( !R_VkTextureUpload( insert.index, tex, &pic, 1, colorspace_hint ))
if( !R_VkTextureUpload( index, tex, &pic, 1, colorspace_hint ))
{ {
// FIXME remove from hash table if (insert.created)
memset( tex, 0, sizeof( vk_texture_t )); urmomRemoveByIndex(&g_textures.all_desc, insert.index);
gEngine.FS_FreeImage( pic ); // release source texture gEngine.FS_FreeImage( pic ); // release source texture
return 0; return 0;
} }
gEngine.FS_FreeImage( pic ); // release source texture
// FIXME this is not strictly correct. Refcount management should be done differently wrt public ref_interface_t
// TODO where did we come from?
if (insert.created)
tex->refcount = 1;
tex->width = pic->width; tex->width = pic->width;
tex->height = pic->height; tex->height = pic->height;
gEngine.FS_FreeImage( pic ); // release source texture return insert.index;
// NOTE: always return texnum as index in array or engine will stop work !!!
return index;
} }
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 ) {
@ -672,43 +677,55 @@ void R_TextureFree( unsigned int texnum ) {
} }
static int loadTextureFromBuffers( const char *name, rgbdata_t *const *const pic, int pic_count, texFlags_t flags, qboolean update_only ) { static int loadTextureFromBuffers( const char *name, rgbdata_t *const *const pic, int pic_count, texFlags_t flags, qboolean update_only ) {
vk_texture_t *tex; // couldn't loading image
if( !pic )
if( !Common_CheckTexName( name ))
return 0; return 0;
// see if already loaded if( !checkTextureName( name ))
if(( tex = Common_TextureForName( name )) && !update_only ) return 0;
return (tex - vk_textures);
// couldn't loading image urmom_insert_t insert = {0};
if( !pic ) return 0; if (update_only)
insert.index = urmomFind(&g_textures.all_desc, name);
else
insert = urmomInsert(&g_textures.all_desc, name);
if (insert.index < 0) {
if (update_only) {
gEngine.Host_Error( "%s: couldn't find texture %s for update\n", __FUNCTION__, name );
} else {
ERR("Cannot allocate texture slot for \"%s\"", name);
}
return 0;
}
ASSERT(insert.index < COUNTOF(g_textures.all));
vk_texture_t *const tex = g_textures.all + insert.index;
// see if already loaded
if (!insert.created && !update_only)
return insert.index;
if( update_only ) if( update_only )
{
if( tex == NULL )
gEngine.Host_Error( "loadTextureFromBuffer: couldn't find texture %s for update\n", name );
SetBits( tex->flags, flags ); SetBits( tex->flags, flags );
}
else
{
// allocate the new one
ASSERT(!tex);
tex = Common_AllocTexture( name, flags );
}
for (int i = 0; i < pic_count; ++i) for (int i = 0; i < pic_count; ++i)
VK_ProcessImage( tex, pic[i] ); VK_ProcessImage( tex, pic[i] );
if( !R_VkTextureUpload( (int)(tex - vk_textures), tex, pic, pic_count, kColorspaceGamma )) if( !R_VkTextureUpload( insert.index, tex, pic, pic_count, kColorspaceGamma ))
{ {
memset( tex, 0, sizeof( vk_texture_t )); if (!update_only)
urmomRemoveByIndex(&g_textures.all_desc, insert.index);
return 0; return 0;
} }
return (tex - vk_textures); // FIXME this is not strictly correct. Refcount management should be done differently wrt public ref_interface_t
} // TODO where did we come from?
if (insert.created)
tex->refcount = 1;
return insert.index;
}
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 ) {
return loadTextureFromBuffers(name, &pic, 1, flags, update_only); return loadTextureFromBuffers(name, &pic, 1, flags, update_only);
} }
@ -798,7 +815,7 @@ static qboolean loadSkybox( const char *prefix, int style ) {
if( i != 6 ) if( i != 6 )
goto cleanup; goto cleanup;
if( !Common_CheckTexName( prefix )) if( !checkTextureName( prefix ))
goto cleanup; goto cleanup;
@ -911,12 +928,16 @@ int R_TextureCreateDummy_FIXME( const char *name ) {
return R_TextureUploadFromBufferNew(name, pic, TF_NOMIPMAP); return R_TextureUploadFromBufferNew(name, pic, TF_NOMIPMAP);
} }
struct vk_texture_s *R_TextureGetByIndex( uint index) struct vk_texture_s *R_TextureGetByIndex( uint index )
{ {
ASSERT(index >= 0); ASSERT(index >= 0);
ASSERT(index < MAX_TEXTURES); ASSERT(index < MAX_TEXTURES);
//return g_vktextures.textures + index; //return g_vktextures.textures + index;
return vk_textures + index;
vk_texture_t *const tex = g_textures.all + index;
if (!URMOM_IS_OCCUPIED(tex->hdr_))
WARN("Accessing empty texture %d", index);
return tex;
} }
int R_TexturesGetParm( int parm, int arg ) { int R_TexturesGetParm( int parm, int arg ) {
@ -949,11 +970,10 @@ int R_TexturesGetParm( int parm, int arg ) {
} }
void R_TextureAcquire( unsigned int texnum ) { void R_TextureAcquire( unsigned int texnum ) {
ASSERT(texnum < vk_numTextures); vk_texture_t *const tex = R_TextureGetByIndex(texnum);
vk_texture_t *const tex = vk_textures + texnum;
++tex->refcount; ++tex->refcount;
DEBUG("Acquiring existing texture %s(%d) refcount=%d", tex->name, (int)(tex-vk_textures), tex->refcount); DEBUG("Acquiring existing texture %s(%d) refcount=%d", TEX_NAME(tex), texnum, tex->refcount);
} }
void R_TextureRelease( unsigned int texnum ) { void R_TextureRelease( unsigned int texnum ) {
@ -966,43 +986,34 @@ void R_TextureRelease( unsigned int texnum ) {
if( texnum <= 0 ) if( texnum <= 0 )
goto end; goto end;
tex = vk_textures + texnum; ASSERT(texnum < COUNTOF(g_textures.all));
tex = g_textures.all + texnum;
// already freed? // already freed?
if( !tex->vk.image.image ) if( !tex->vk.image.image )
goto end; goto end;
// debug // debug
if( !tex->name[0] ) if( !TEX_NAME(tex)[0] )
{ {
ERR("R_TextureRelease: trying to free unnamed texture with index %u", texnum ); ERR("R_TextureRelease: trying to free unnamed texture with index %u", texnum );
goto end; goto end;
} }
DEBUG("Releasing texture=%d(%s) refcount=%d", texnum, tex->name, tex->refcount); DEBUG("Releasing texture=%d(%s) refcount=%d", texnum, TEX_NAME(tex), tex->refcount);
ASSERT(tex->refcount > 0); ASSERT(tex->refcount > 0);
--tex->refcount; --tex->refcount;
if (tex->refcount > 0) if (tex->refcount > 0)
goto end; goto end;
DEBUG("Freeing texture=%d(%s)", texnum, tex->name); DEBUG("Freeing texture=%d(%s)", texnum, TEX_NAME(tex));
ASSERT(URMOM_IS_OCCUPIED(tex->hdr_));
// remove from hash table // remove from hash table
prev = &vk_texturesHashTable[tex->hashValue]; urmomRemoveByIndex(&g_textures.all_desc, texnum);
while( 1 )
{
cur = *prev;
if( !cur ) break;
if( cur == tex )
{
*prev = cur->nextHash;
break;
}
prev = &cur->nextHash;
}
/* /*
// release source // release source
@ -1011,7 +1022,6 @@ void R_TextureRelease( unsigned int texnum ) {
*/ */
R_VkTextureDestroy( texnum, tex ); R_VkTextureDestroy( texnum, tex );
memset(tex, 0, sizeof(*tex));
end: end:
APROF_SCOPE_END(free); APROF_SCOPE_END(free);

View File

@ -51,16 +51,22 @@ typedef struct {
static int test_insert_find_remove( void ) { static int test_insert_find_remove( void ) {
PREAMBLE(4); PREAMBLE(4);
const int i = urmomInsert(&desc, "bidonchik"); const urmom_insert_t i = urmomInsert(&desc, "bidonchik");
CHECK_NOT_EQUAL_I(i, -1); CHECK_NOT_EQUAL_I(i.index, -1);
CHECK_EQUAL_S(items[i].hdr_.key, "bidonchik"); CHECK_EQUAL_I(i.created, 1);
CHECK_EQUAL_S(items[i.index].hdr_.key, "bidonchik");
const int found = urmomFind(&desc, "bidonchik"); const int found = urmomFind(&desc, "bidonchik");
CHECK_EQUAL_I(found, i); CHECK_EQUAL_I(found, i.index);
const urmom_insert_t i2 = urmomInsert(&desc, "bidonchik");
CHECK_EQUAL_I(i2.index, i.index);
CHECK_EQUAL_I(i2.created, 0);
CHECK_EQUAL_S(items[i.index].hdr_.key, "bidonchik");
const int removed = urmomRemove(&desc, "bidonchik"); const int removed = urmomRemove(&desc, "bidonchik");
CHECK_EQUAL_I(removed, i); CHECK_EQUAL_I(removed, i.index);
CHECK_EQUAL_I(items[i].hdr_.key[0], '\0'); CHECK_EQUAL_I(items[i.index].hdr_.key[0], '\0');
const int not_found = urmomFind(&desc, "bidonchik"); const int not_found = urmomFind(&desc, "bidonchik");
CHECK_EQUAL_I(not_found, -1); CHECK_EQUAL_I(not_found, -1);
@ -79,20 +85,22 @@ static int test_find_nonexistent( void ) {
static int test_insert_find_many( void ) { static int test_insert_find_many( void ) {
PREAMBLE(4); PREAMBLE(4);
const int a = urmomInsert(&desc, "smetanka"); const urmom_insert_t a = urmomInsert(&desc, "smetanka");
CHECK_NOT_EQUAL_I(a, -1); CHECK_NOT_EQUAL_I(a.index, -1);
CHECK_EQUAL_S(items[a].hdr_.key, "smetanka"); CHECK_EQUAL_I(a.created, 1);
CHECK_EQUAL_S(items[a.index].hdr_.key, "smetanka");
const int b = urmomInsert(&desc, "tworog"); const urmom_insert_t b = urmomInsert(&desc, "tworog");
CHECK_NOT_EQUAL_I(b, -1); CHECK_NOT_EQUAL_I(b.index, -1);
CHECK_NOT_EQUAL_I(a, b); CHECK_EQUAL_I(b.created, 1);
CHECK_EQUAL_S(items[b].hdr_.key, "tworog"); CHECK_NOT_EQUAL_I(a.index, b.index);
CHECK_EQUAL_S(items[b.index].hdr_.key, "tworog");
const int a_found = urmomFind(&desc, "smetanka"); const int a_found = urmomFind(&desc, "smetanka");
const int b_found = urmomFind(&desc, "tworog"); const int b_found = urmomFind(&desc, "tworog");
CHECK_EQUAL_I(a_found, a); CHECK_EQUAL_I(a_found, a.index);
CHECK_EQUAL_I(b_found, b); CHECK_EQUAL_I(b_found, b.index);
return 1; return 1;
} }
@ -100,46 +108,52 @@ static int test_insert_find_many( void ) {
static int test_overflow( void ) { static int test_overflow( void ) {
PREAMBLE(4); PREAMBLE(4);
const int a = urmomInsert(&desc, "smetanka"); const urmom_insert_t a = urmomInsert(&desc, "smetanka");
CHECK_NOT_EQUAL_I(a, -1); CHECK_NOT_EQUAL_I(a.index, -1);
CHECK_EQUAL_S(items[a].hdr_.key, "smetanka"); CHECK_EQUAL_I(a.created, 1);
CHECK_EQUAL_S(items[a.index].hdr_.key, "smetanka");
const int b = urmomInsert(&desc, "tworog"); const urmom_insert_t b = urmomInsert(&desc, "tworog");
CHECK_NOT_EQUAL_I(b, -1); CHECK_NOT_EQUAL_I(b.index, -1);
CHECK_NOT_EQUAL_I(a, b); CHECK_EQUAL_I(b.created, 1);
CHECK_EQUAL_S(items[b].hdr_.key, "tworog"); CHECK_NOT_EQUAL_I(a.index, b.index);
CHECK_EQUAL_S(items[b.index].hdr_.key, "tworog");
const int c = urmomInsert(&desc, "kefirushka"); const urmom_insert_t c = urmomInsert(&desc, "kefirushka");
CHECK_NOT_EQUAL_I(c, -1); CHECK_NOT_EQUAL_I(c.index, -1);
CHECK_NOT_EQUAL_I(a, c); CHECK_EQUAL_I(c.created, 1);
CHECK_NOT_EQUAL_I(b, c); CHECK_NOT_EQUAL_I(a.index, c.index);
CHECK_EQUAL_S(items[c].hdr_.key, "kefirushka"); CHECK_NOT_EQUAL_I(b.index, c.index);
CHECK_EQUAL_S(items[c.index].hdr_.key, "kefirushka");
const int d = urmomInsert(&desc, "ryazhenka"); const urmom_insert_t d = urmomInsert(&desc, "ryazhenka");
CHECK_NOT_EQUAL_I(d, -1); CHECK_NOT_EQUAL_I(d.index, -1);
CHECK_NOT_EQUAL_I(a, d); CHECK_EQUAL_I(d.created, 1);
CHECK_NOT_EQUAL_I(b, d); CHECK_NOT_EQUAL_I(a.index, d.index);
CHECK_NOT_EQUAL_I(c, d); CHECK_NOT_EQUAL_I(b.index, d.index);
CHECK_EQUAL_S(items[d].hdr_.key, "ryazhenka"); CHECK_NOT_EQUAL_I(c.index, d.index);
CHECK_EQUAL_S(items[d.index].hdr_.key, "ryazhenka");
{ {
const int e = urmomInsert(&desc, "riajenka"); const urmom_insert_t e = urmomInsert(&desc, "riajenka");
CHECK_EQUAL_I(e, -1); CHECK_EQUAL_I(e.index, -1);
CHECK_EQUAL_I(e.created, 0);
} }
const int d_remove = urmomRemove(&desc, "ryazhenka"); const int d_remove = urmomRemove(&desc, "ryazhenka");
CHECK_EQUAL_I(d_remove, d); CHECK_EQUAL_I(d_remove, d.index);
CHECK_EQUAL_I(items[d_remove].hdr_.state, 0); CHECK_EQUAL_I(items[d_remove].hdr_.state, 0);
CHECK_NOT_EQUAL_I(items[d_remove].hdr_.hash, 0); CHECK_NOT_EQUAL_I(items[d_remove].hdr_.hash, 0);
CHECK_EQUAL_I(items[d_remove].hdr_.key[0], '\0'); CHECK_EQUAL_I(items[d_remove].hdr_.key[0], '\0');
const int e = urmomInsert(&desc, "riajenka"); const urmom_insert_t e = urmomInsert(&desc, "riajenka");
CHECK_NOT_EQUAL_I(e, -1); CHECK_NOT_EQUAL_I(e.index, -1);
CHECK_NOT_EQUAL_I(a, e); CHECK_EQUAL_I(e.created, 1);
CHECK_NOT_EQUAL_I(b, e); CHECK_NOT_EQUAL_I(a.index, e.index);
CHECK_NOT_EQUAL_I(c, e); CHECK_NOT_EQUAL_I(b.index, e.index);
CHECK_EQUAL_S(items[e].hdr_.key, "riajenka"); CHECK_NOT_EQUAL_I(c.index, e.index);
CHECK_EQUAL_S(items[e.index].hdr_.key, "riajenka");
return 1; return 1;
} }
@ -148,20 +162,22 @@ static int test_overflow( void ) {
static int test_hash_collision( void ) { static int test_hash_collision( void ) {
PREAMBLE(4); PREAMBLE(4);
const int a = urmomInsert(&desc, "costarring"); const urmom_insert_t a = urmomInsert(&desc, "costarring");
CHECK_NOT_EQUAL_I(a, -1); CHECK_NOT_EQUAL_I(a.index, -1);
CHECK_EQUAL_I(a.created, 1);
const int b = urmomInsert(&desc, "liquid"); const urmom_insert_t b = urmomInsert(&desc, "liquid");
CHECK_NOT_EQUAL_I(b, -1); CHECK_NOT_EQUAL_I(b.index, -1);
CHECK_NOT_EQUAL_I(b, a); CHECK_EQUAL_I(b.created, 1);
CHECK_NOT_EQUAL_I(b.index, a.index);
CHECK_EQUAL_I(items[a].hdr_.hash, items[b].hdr_.hash); CHECK_EQUAL_I(items[a.index].hdr_.hash, items[b.index].hdr_.hash);
const int a_found = urmomFind(&desc, "costarring"); const int a_found = urmomFind(&desc, "costarring");
CHECK_EQUAL_I(a_found, a); CHECK_EQUAL_I(a_found, a.index);
const int b_found = urmomFind(&desc, "liquid"); const int b_found = urmomFind(&desc, "liquid");
CHECK_EQUAL_I(b_found, b); CHECK_EQUAL_I(b_found, b.index);
return 1; return 1;
} }

View File

@ -68,50 +68,61 @@ int urmomFind(const urmom_desc_t* desc, const char* key) {
} }
// Returns index of the element either found or empty slot where this could be inserted. If full, -1. // Returns index of the element either found or empty slot where this could be inserted. If full, -1.
int urmomInsert(const urmom_desc_t* desc, const char *key) { urmom_insert_t urmomInsert(const urmom_desc_t* desc, const char *key) {
char *ptr = desc->array; char *ptr = desc->array;
const uint32_t hash = hash32FNV1aStr(key) & 0x7fffffffu; const uint32_t hash = hash32FNV1aStr(key) & 0x7fffffffu;
const uint32_t mask = (desc->count - 1); const uint32_t mask = (desc->count - 1);
const int start_index = hash & mask; const int start_index = hash & mask;
int index = start_index; int index = start_index;
int first_available = -1;
for (;;) { for (;;) {
const urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index); const urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index);
if (URMOM_IS_OCCUPIED(*hdr)) { if (URMOM_IS_OCCUPIED(*hdr)) {
if (hdr->hash == hash && strcmp(key, hdr->key) == 0) if (hdr->hash == hash && strcmp(key, hdr->key) == 0)
// Return existing item // Return existing item
return index; return (urmom_insert_t){.index = index, .created = 0};
} else } else {
// Remember the very first item that wasn't occupied
if (first_available < 0)
first_available = index;
// Reached the end of occupied chain, return the available slot // Reached the end of occupied chain, return the available slot
break; if (URMOM_IS_EMPTY(*hdr))
break;
}
index = (index + 1) & mask; index = (index + 1) & mask;
// Searched through the entire thing // Searched through the entire thing
if (index == start_index) if (index == start_index)
return -1; break;
} }
urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index); // If no slots were encountered, exit with error
if (first_available < 0)
return (urmom_insert_t){.index = -1, .created = 0};
urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * first_available);
hdr->hash = hash; hdr->hash = hash;
hdr->state = 1; hdr->state = 1;
// TODO check for key length // TODO check for key length
strncpy(hdr->key, key, sizeof(hdr->key)); strncpy(hdr->key, key, sizeof(hdr->key));
return index; return (urmom_insert_t){.index = first_available, .created = 1};
} }
// Return the index of item deleted (if found), -1 otherwise // Return the index of item deleted (if found), -1 otherwise
int urmomRemove(const urmom_desc_t* desc, const char *key) { int urmomRemove(const urmom_desc_t* desc, const char *key) {
const int index = urmomFind(desc, key); const int index = urmomFind(desc, key);
if (index >= 0) if (index >= 0)
urmomDeleteByIndex(desc, index); urmomRemoveByIndex(desc, index);
return index; return index;
} }
void urmomDeleteByIndex(const urmom_desc_t* desc, int index) { void urmomRemoveByIndex(const urmom_desc_t* desc, int index) {
char *ptr = desc->array; char *ptr = desc->array;
urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index); urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index);

View File

@ -40,9 +40,13 @@ void urmomInit(const urmom_desc_t* desc);
int urmomFind(const urmom_desc_t* desc, const char* key); int urmomFind(const urmom_desc_t* desc, const char* key);
// Returns index of the element either found or empty slot where this could be inserted. If full, -1. // Returns index of the element either found or empty slot where this could be inserted. If full, -1.
int urmomInsert(const urmom_desc_t* desc, const char *key); typedef struct urmom_insert_s {
int index;
void urmomDeleteByIndex(const urmom_desc_t* desc, int index); int created;
} urmom_insert_t;
urmom_insert_t urmomInsert(const urmom_desc_t* desc, const char *key);
// Return the index of item deleted (if found), -1 otherwise // Return the index of item deleted (if found), -1 otherwise
int urmomRemove(const urmom_desc_t* desc, const char *key); int urmomRemove(const urmom_desc_t* desc, const char *key);
void urmomRemoveByIndex(const urmom_desc_t* desc, int index);

View File

@ -253,7 +253,7 @@ static void setDescriptorSet(int index, vk_texture_t* const tex, colorspace_hint
} }
static qboolean uploadRawKtx2( int tex_index, vk_texture_t *tex, const rgbdata_t* pic ) { static qboolean uploadRawKtx2( int tex_index, vk_texture_t *tex, const rgbdata_t* pic ) {
DEBUG("Uploading raw KTX2 texture[%d] %s", tex_index, tex->name); DEBUG("Uploading raw KTX2 texture[%d] %s", tex_index, TEX_NAME(tex));
const byte *const data = pic->buffer; const byte *const data = pic->buffer;
const int size = pic->size; const int size = pic->size;
@ -303,7 +303,7 @@ static qboolean uploadRawKtx2( int tex_index, vk_texture_t *tex, const rgbdata_t
{ {
const r_vk_image_create_t create = { const r_vk_image_create_t create = {
.debug_name = tex->name, .debug_name = TEX_NAME(tex),
.width = header->pixelWidth, .width = header->pixelWidth,
.height = header->pixelHeight, .height = header->pixelHeight,
.mips = header->levelCount, .mips = header->levelCount,
@ -373,13 +373,13 @@ static qboolean uploadTexture(int index, vk_texture_t *tex, rgbdata_t *const *co
return false; return false;
} }
if (!validatePicLayers(tex->name, layers, num_layers)) if (!validatePicLayers(TEX_NAME(tex), layers, num_layers))
return false; return false;
tex->width = layers[0]->width; tex->width = layers[0]->width;
tex->height = layers[0]->height; tex->height = layers[0]->height;
DEBUG("Uploading texture[%d] %s, mips=%d(build=%d), layers=%d", index, tex->name, mipCount, compute_mips, num_layers); DEBUG("Uploading texture[%d] %s, mips=%d(build=%d), layers=%d", index, TEX_NAME(tex), mipCount, compute_mips, num_layers);
// TODO (not sure why, but GL does this) // TODO (not sure why, but GL does this)
// if( !ImageCompressed( layers->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( layers->flags, IMAGE_ONEBIT_ALPHA )) // if( !ImageCompressed( layers->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( layers->flags, IMAGE_ONEBIT_ALPHA ))
@ -391,7 +391,7 @@ static qboolean uploadTexture(int index, vk_texture_t *tex, rgbdata_t *const *co
{ {
const r_vk_image_create_t create = { const r_vk_image_create_t create = {
.debug_name = tex->name, .debug_name = TEX_NAME(tex),
.width = tex->width, .width = tex->width,
.height = tex->height, .height = tex->height,
.mips = mipCount, .mips = mipCount,
@ -462,6 +462,7 @@ void R_VkTextureDestroy( int index, vk_texture_t *tex ) {
setDescriptorSet(index, tex, kColorspaceNative); setDescriptorSet(index, tex, kColorspaceNative);
tex->total_size = 0; tex->total_size = 0;
tex->width = tex->height = 0;
// TODO: currently cannot do this because vk_render depends on all textures having some descriptor regardless of their alive-ness // TODO: currently cannot do this because vk_render depends on all textures having some descriptor regardless of their alive-ness
// TODO tex->vk.descriptor_unorm = VK_NULL_HANDLE; // TODO tex->vk.descriptor_unorm = VK_NULL_HANDLE;
@ -488,7 +489,7 @@ VkDescriptorImageInfo R_VkTextureGetSkyboxDescriptorImageInfo( 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) {
vk_texture_t *const dest = placeholder ? &g_vktextures.cubemap_placeholder : &g_vktextures.skybox_cube; vk_texture_t *const dest = placeholder ? &g_vktextures.cubemap_placeholder : &g_vktextures.skybox_cube;
Q_strncpy( dest->name, name, sizeof( dest->name )); Q_strncpy( TEX_NAME(dest), name, sizeof( TEX_NAME(dest) ));
return uploadTexture(-1, dest, sides, 6, true, colorspace_hint); return uploadTexture(-1, dest, sides, 6, true, colorspace_hint);
} }

View File

@ -1,14 +1,17 @@
#pragma once #pragma once
#include "r_textures.h" #include "r_textures.h"
#include "vk_core.h" #include "vk_core.h"
#include "vk_image.h" #include "vk_image.h"
#include "vk_const.h" #include "vk_const.h"
#include "unordered_roadmap.h"
typedef struct vk_texture_s typedef struct vk_texture_s
{ {
char name[256]; urmom_header_t hdr_;
//char name[256];
int width, height; int width, height;
uint32_t flags; uint32_t flags;
@ -19,17 +22,14 @@ typedef struct vk_texture_s
VkDescriptorSet descriptor_unorm; VkDescriptorSet descriptor_unorm;
} vk; } vk;
// Internals for hash table
uint texnum;
uint hashValue;
struct vk_texture_s *nextHash;
int refcount; int refcount;
// TODO "cache" eviction // TODO "cache" eviction
// int used_maps_ago; // int used_maps_ago;
} vk_texture_t; } vk_texture_t;
#define TEX_NAME(tex) ((tex)->hdr_.key)
typedef enum { typedef enum {
kColorspaceNative, kColorspaceNative,
kColorspaceLinear, kColorspaceLinear,