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:
parent
beddef8831
commit
718d6d2592
|
@ -7,6 +7,7 @@
|
|||
#include "vk_logs.h"
|
||||
#include "r_speeds.h"
|
||||
#include "profiler.h"
|
||||
#include "unordered_roadmap.h"
|
||||
|
||||
#define PCG_IMPLEMENT
|
||||
#include "pcg.h"
|
||||
|
@ -23,16 +24,13 @@
|
|||
#define LOG_MODULE LogModule_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};
|
||||
|
||||
static struct {
|
||||
poolhandle_t mempool;
|
||||
|
||||
vk_texture_t all[MAX_TEXTURES];
|
||||
urmom_desc_t all_desc;
|
||||
} g_textures;
|
||||
|
||||
// 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 ) {
|
||||
g_textures.mempool = Mem_AllocPool( "vktextures" );
|
||||
|
||||
memset( vk_textures, 0, sizeof( vk_textures ));
|
||||
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
|
||||
vk_numTextures = 0;
|
||||
g_textures.all_desc = (urmom_desc_t){
|
||||
.array = g_textures.all,
|
||||
.count = COUNTOF(g_textures.all),
|
||||
.item_size = sizeof(g_textures.all[0]),
|
||||
};
|
||||
|
||||
// create unused 0-entry
|
||||
Q_strncpy( vk_textures->name, "*unused*", sizeof( vk_textures->name ));
|
||||
vk_textures->hashValue = COM_HashKey( vk_textures->name, TEXTURES_HASH_SIZE );
|
||||
vk_textures->nextHash = vk_texturesHashTable[vk_textures->hashValue];
|
||||
vk_texturesHashTable[vk_textures->hashValue] = vk_textures;
|
||||
vk_numTextures = 1;
|
||||
urmomInit(&g_textures.all_desc);
|
||||
|
||||
// Mark index 0 as occupied to have a special "no texture" value
|
||||
g_textures.all[0].hdr_.hash = 0x7fffffff;
|
||||
g_textures.all[0].hdr_.state = 1;
|
||||
Q_strncpy( g_textures.all[0].hdr_.key, "*unused*", sizeof(g_textures.all[0].hdr_.key));
|
||||
|
||||
createDefaultTextures();
|
||||
|
||||
|
@ -65,17 +65,13 @@ qboolean R_TexturesInit( 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_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 )
|
||||
{
|
||||
vk_texture_t *tex;
|
||||
|
@ -109,25 +105,6 @@ static vk_texture_t *Common_AllocTexture( const char *name, texFlags_t flags )
|
|||
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 )
|
||||
{
|
||||
vk_texture_t *tex;
|
||||
|
@ -144,6 +121,26 @@ static vk_texture_t *Common_TextureForName( const char *name )
|
|||
|
||||
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 )
|
||||
{
|
||||
|
@ -311,7 +308,7 @@ static void createDefaultTextures( void )
|
|||
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;
|
||||
|
||||
if( !Common_CheckTexName( name ))
|
||||
if( !checkTextureName( name ))
|
||||
return 0;
|
||||
|
||||
// see if already loaded
|
||||
if(( tex = Common_TextureForName( name )))
|
||||
return (tex - vk_textures);
|
||||
|
||||
return 0;
|
||||
const int index = urmomFind(&g_textures.all_desc, name);
|
||||
return index ? index > 0 : 0;
|
||||
}
|
||||
|
||||
const char* R_TextureGetNameByIndex( unsigned int texnum )
|
||||
{
|
||||
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 ) {
|
||||
if( !Common_CheckTexName( name ))
|
||||
if( !checkTextureName( name ))
|
||||
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
|
||||
vk_texture_t * tex = Common_TextureForName( name );
|
||||
if( tex && !force_update ) {
|
||||
DEBUG("Found existing texture %s(%d) refcount=%d", tex->name, (int)(tex-vk_textures), tex->refcount);
|
||||
return (tex - vk_textures);
|
||||
if (!insert.created && !force_update) {
|
||||
DEBUG("Found existing texture %s(%d) refcount=%d",
|
||||
TEX_NAME(tex), insert.index, tex->refcount);
|
||||
return insert.index;
|
||||
}
|
||||
|
||||
uint picFlags = 0;
|
||||
|
@ -616,33 +617,37 @@ static int loadTextureInternal( const char *name, const byte *buf, size_t size,
|
|||
gEngine.Image_SetForceFlags( picFlags );
|
||||
|
||||
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
|
||||
if (!tex)
|
||||
tex = Common_AllocTexture( name, flags );
|
||||
else
|
||||
tex->flags = flags;
|
||||
tex->flags = flags;
|
||||
|
||||
// upload texture
|
||||
VK_ProcessImage( tex, pic );
|
||||
|
||||
const int index = (tex - vk_textures);
|
||||
if( !R_VkTextureUpload( index, tex, &pic, 1, colorspace_hint ))
|
||||
if( !R_VkTextureUpload( insert.index, tex, &pic, 1, colorspace_hint ))
|
||||
{
|
||||
// FIXME remove from hash table
|
||||
memset( tex, 0, sizeof( vk_texture_t ));
|
||||
if (insert.created)
|
||||
urmomRemoveByIndex(&g_textures.all_desc, insert.index);
|
||||
|
||||
gEngine.FS_FreeImage( pic ); // release source texture
|
||||
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->height = pic->height;
|
||||
|
||||
gEngine.FS_FreeImage( pic ); // release source texture
|
||||
|
||||
// NOTE: always return texnum as index in array or engine will stop work !!!
|
||||
return index;
|
||||
return insert.index;
|
||||
}
|
||||
|
||||
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 ) {
|
||||
vk_texture_t *tex;
|
||||
|
||||
if( !Common_CheckTexName( name ))
|
||||
// couldn't loading image
|
||||
if( !pic )
|
||||
return 0;
|
||||
|
||||
// see if already loaded
|
||||
if(( tex = Common_TextureForName( name )) && !update_only )
|
||||
return (tex - vk_textures);
|
||||
if( !checkTextureName( name ))
|
||||
return 0;
|
||||
|
||||
// couldn't loading image
|
||||
if( !pic ) return 0;
|
||||
urmom_insert_t insert = {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( tex == NULL )
|
||||
gEngine.Host_Error( "loadTextureFromBuffer: couldn't find texture %s for update\n", name );
|
||||
SetBits( tex->flags, flags );
|
||||
}
|
||||
else
|
||||
{
|
||||
// allocate the new one
|
||||
ASSERT(!tex);
|
||||
tex = Common_AllocTexture( name, flags );
|
||||
}
|
||||
|
||||
for (int i = 0; i < pic_count; ++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 (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 ) {
|
||||
return loadTextureFromBuffers(name, &pic, 1, flags, update_only);
|
||||
}
|
||||
|
@ -798,7 +815,7 @@ static qboolean loadSkybox( const char *prefix, int style ) {
|
|||
if( i != 6 )
|
||||
goto cleanup;
|
||||
|
||||
if( !Common_CheckTexName( prefix ))
|
||||
if( !checkTextureName( prefix ))
|
||||
goto cleanup;
|
||||
|
||||
|
||||
|
@ -911,12 +928,16 @@ int R_TextureCreateDummy_FIXME( const char *name ) {
|
|||
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 < MAX_TEXTURES);
|
||||
//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 ) {
|
||||
|
@ -949,11 +970,10 @@ int R_TexturesGetParm( int parm, int arg ) {
|
|||
}
|
||||
|
||||
void R_TextureAcquire( unsigned int texnum ) {
|
||||
ASSERT(texnum < vk_numTextures);
|
||||
vk_texture_t *const tex = vk_textures + texnum;
|
||||
vk_texture_t *const tex = R_TextureGetByIndex(texnum);
|
||||
++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 ) {
|
||||
|
@ -966,43 +986,34 @@ void R_TextureRelease( unsigned int texnum ) {
|
|||
if( texnum <= 0 )
|
||||
goto end;
|
||||
|
||||
tex = vk_textures + texnum;
|
||||
ASSERT(texnum < COUNTOF(g_textures.all));
|
||||
|
||||
tex = g_textures.all + texnum;
|
||||
|
||||
// already freed?
|
||||
if( !tex->vk.image.image )
|
||||
goto end;
|
||||
|
||||
// debug
|
||||
if( !tex->name[0] )
|
||||
if( !TEX_NAME(tex)[0] )
|
||||
{
|
||||
ERR("R_TextureRelease: trying to free unnamed texture with index %u", texnum );
|
||||
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);
|
||||
--tex->refcount;
|
||||
|
||||
if (tex->refcount > 0)
|
||||
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
|
||||
prev = &vk_texturesHashTable[tex->hashValue];
|
||||
|
||||
while( 1 )
|
||||
{
|
||||
cur = *prev;
|
||||
if( !cur ) break;
|
||||
|
||||
if( cur == tex )
|
||||
{
|
||||
*prev = cur->nextHash;
|
||||
break;
|
||||
}
|
||||
prev = &cur->nextHash;
|
||||
}
|
||||
urmomRemoveByIndex(&g_textures.all_desc, texnum);
|
||||
|
||||
/*
|
||||
// release source
|
||||
|
@ -1011,7 +1022,6 @@ void R_TextureRelease( unsigned int texnum ) {
|
|||
*/
|
||||
|
||||
R_VkTextureDestroy( texnum, tex );
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
|
||||
end:
|
||||
APROF_SCOPE_END(free);
|
||||
|
|
|
@ -51,16 +51,22 @@ typedef struct {
|
|||
static int test_insert_find_remove( void ) {
|
||||
PREAMBLE(4);
|
||||
|
||||
const int i = urmomInsert(&desc, "bidonchik");
|
||||
CHECK_NOT_EQUAL_I(i, -1);
|
||||
CHECK_EQUAL_S(items[i].hdr_.key, "bidonchik");
|
||||
const urmom_insert_t i = urmomInsert(&desc, "bidonchik");
|
||||
CHECK_NOT_EQUAL_I(i.index, -1);
|
||||
CHECK_EQUAL_I(i.created, 1);
|
||||
CHECK_EQUAL_S(items[i.index].hdr_.key, "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");
|
||||
CHECK_EQUAL_I(removed, i);
|
||||
CHECK_EQUAL_I(items[i].hdr_.key[0], '\0');
|
||||
CHECK_EQUAL_I(removed, i.index);
|
||||
CHECK_EQUAL_I(items[i.index].hdr_.key[0], '\0');
|
||||
|
||||
const int not_found = urmomFind(&desc, "bidonchik");
|
||||
CHECK_EQUAL_I(not_found, -1);
|
||||
|
@ -79,20 +85,22 @@ static int test_find_nonexistent( void ) {
|
|||
static int test_insert_find_many( void ) {
|
||||
PREAMBLE(4);
|
||||
|
||||
const int a = urmomInsert(&desc, "smetanka");
|
||||
CHECK_NOT_EQUAL_I(a, -1);
|
||||
CHECK_EQUAL_S(items[a].hdr_.key, "smetanka");
|
||||
const urmom_insert_t a = urmomInsert(&desc, "smetanka");
|
||||
CHECK_NOT_EQUAL_I(a.index, -1);
|
||||
CHECK_EQUAL_I(a.created, 1);
|
||||
CHECK_EQUAL_S(items[a.index].hdr_.key, "smetanka");
|
||||
|
||||
const int b = urmomInsert(&desc, "tworog");
|
||||
CHECK_NOT_EQUAL_I(b, -1);
|
||||
CHECK_NOT_EQUAL_I(a, b);
|
||||
CHECK_EQUAL_S(items[b].hdr_.key, "tworog");
|
||||
const urmom_insert_t b = urmomInsert(&desc, "tworog");
|
||||
CHECK_NOT_EQUAL_I(b.index, -1);
|
||||
CHECK_EQUAL_I(b.created, 1);
|
||||
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 b_found = urmomFind(&desc, "tworog");
|
||||
|
||||
CHECK_EQUAL_I(a_found, a);
|
||||
CHECK_EQUAL_I(b_found, b);
|
||||
CHECK_EQUAL_I(a_found, a.index);
|
||||
CHECK_EQUAL_I(b_found, b.index);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -100,46 +108,52 @@ static int test_insert_find_many( void ) {
|
|||
static int test_overflow( void ) {
|
||||
PREAMBLE(4);
|
||||
|
||||
const int a = urmomInsert(&desc, "smetanka");
|
||||
CHECK_NOT_EQUAL_I(a, -1);
|
||||
CHECK_EQUAL_S(items[a].hdr_.key, "smetanka");
|
||||
const urmom_insert_t a = urmomInsert(&desc, "smetanka");
|
||||
CHECK_NOT_EQUAL_I(a.index, -1);
|
||||
CHECK_EQUAL_I(a.created, 1);
|
||||
CHECK_EQUAL_S(items[a.index].hdr_.key, "smetanka");
|
||||
|
||||
const int b = urmomInsert(&desc, "tworog");
|
||||
CHECK_NOT_EQUAL_I(b, -1);
|
||||
CHECK_NOT_EQUAL_I(a, b);
|
||||
CHECK_EQUAL_S(items[b].hdr_.key, "tworog");
|
||||
const urmom_insert_t b = urmomInsert(&desc, "tworog");
|
||||
CHECK_NOT_EQUAL_I(b.index, -1);
|
||||
CHECK_EQUAL_I(b.created, 1);
|
||||
CHECK_NOT_EQUAL_I(a.index, b.index);
|
||||
CHECK_EQUAL_S(items[b.index].hdr_.key, "tworog");
|
||||
|
||||
|
||||
const int c = urmomInsert(&desc, "kefirushka");
|
||||
CHECK_NOT_EQUAL_I(c, -1);
|
||||
CHECK_NOT_EQUAL_I(a, c);
|
||||
CHECK_NOT_EQUAL_I(b, c);
|
||||
CHECK_EQUAL_S(items[c].hdr_.key, "kefirushka");
|
||||
const urmom_insert_t c = urmomInsert(&desc, "kefirushka");
|
||||
CHECK_NOT_EQUAL_I(c.index, -1);
|
||||
CHECK_EQUAL_I(c.created, 1);
|
||||
CHECK_NOT_EQUAL_I(a.index, c.index);
|
||||
CHECK_NOT_EQUAL_I(b.index, c.index);
|
||||
CHECK_EQUAL_S(items[c.index].hdr_.key, "kefirushka");
|
||||
|
||||
const int d = urmomInsert(&desc, "ryazhenka");
|
||||
CHECK_NOT_EQUAL_I(d, -1);
|
||||
CHECK_NOT_EQUAL_I(a, d);
|
||||
CHECK_NOT_EQUAL_I(b, d);
|
||||
CHECK_NOT_EQUAL_I(c, d);
|
||||
CHECK_EQUAL_S(items[d].hdr_.key, "ryazhenka");
|
||||
const urmom_insert_t d = urmomInsert(&desc, "ryazhenka");
|
||||
CHECK_NOT_EQUAL_I(d.index, -1);
|
||||
CHECK_EQUAL_I(d.created, 1);
|
||||
CHECK_NOT_EQUAL_I(a.index, d.index);
|
||||
CHECK_NOT_EQUAL_I(b.index, d.index);
|
||||
CHECK_NOT_EQUAL_I(c.index, d.index);
|
||||
CHECK_EQUAL_S(items[d.index].hdr_.key, "ryazhenka");
|
||||
|
||||
{
|
||||
const int e = urmomInsert(&desc, "riajenka");
|
||||
CHECK_EQUAL_I(e, -1);
|
||||
const urmom_insert_t e = urmomInsert(&desc, "riajenka");
|
||||
CHECK_EQUAL_I(e.index, -1);
|
||||
CHECK_EQUAL_I(e.created, 0);
|
||||
}
|
||||
|
||||
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_NOT_EQUAL_I(items[d_remove].hdr_.hash, 0);
|
||||
CHECK_EQUAL_I(items[d_remove].hdr_.key[0], '\0');
|
||||
|
||||
const int e = urmomInsert(&desc, "riajenka");
|
||||
CHECK_NOT_EQUAL_I(e, -1);
|
||||
CHECK_NOT_EQUAL_I(a, e);
|
||||
CHECK_NOT_EQUAL_I(b, e);
|
||||
CHECK_NOT_EQUAL_I(c, e);
|
||||
CHECK_EQUAL_S(items[e].hdr_.key, "riajenka");
|
||||
const urmom_insert_t e = urmomInsert(&desc, "riajenka");
|
||||
CHECK_NOT_EQUAL_I(e.index, -1);
|
||||
CHECK_EQUAL_I(e.created, 1);
|
||||
CHECK_NOT_EQUAL_I(a.index, e.index);
|
||||
CHECK_NOT_EQUAL_I(b.index, e.index);
|
||||
CHECK_NOT_EQUAL_I(c.index, e.index);
|
||||
CHECK_EQUAL_S(items[e.index].hdr_.key, "riajenka");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -148,20 +162,22 @@ static int test_overflow( void ) {
|
|||
static int test_hash_collision( void ) {
|
||||
PREAMBLE(4);
|
||||
|
||||
const int a = urmomInsert(&desc, "costarring");
|
||||
CHECK_NOT_EQUAL_I(a, -1);
|
||||
const urmom_insert_t a = urmomInsert(&desc, "costarring");
|
||||
CHECK_NOT_EQUAL_I(a.index, -1);
|
||||
CHECK_EQUAL_I(a.created, 1);
|
||||
|
||||
const int b = urmomInsert(&desc, "liquid");
|
||||
CHECK_NOT_EQUAL_I(b, -1);
|
||||
CHECK_NOT_EQUAL_I(b, a);
|
||||
const urmom_insert_t b = urmomInsert(&desc, "liquid");
|
||||
CHECK_NOT_EQUAL_I(b.index, -1);
|
||||
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");
|
||||
CHECK_EQUAL_I(a_found, a);
|
||||
CHECK_EQUAL_I(a_found, a.index);
|
||||
|
||||
const int b_found = urmomFind(&desc, "liquid");
|
||||
CHECK_EQUAL_I(b_found, b);
|
||||
CHECK_EQUAL_I(b_found, b.index);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
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;
|
||||
const uint32_t hash = hash32FNV1aStr(key) & 0x7fffffffu;
|
||||
const uint32_t mask = (desc->count - 1);
|
||||
const int start_index = hash & mask;
|
||||
|
||||
int index = start_index;
|
||||
int first_available = -1;
|
||||
for (;;) {
|
||||
const urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index);
|
||||
|
||||
if (URMOM_IS_OCCUPIED(*hdr)) {
|
||||
if (hdr->hash == hash && strcmp(key, hdr->key) == 0)
|
||||
// Return existing item
|
||||
return index;
|
||||
} else
|
||||
return (urmom_insert_t){.index = index, .created = 0};
|
||||
} 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
|
||||
break;
|
||||
if (URMOM_IS_EMPTY(*hdr))
|
||||
break;
|
||||
}
|
||||
|
||||
index = (index + 1) & mask;
|
||||
|
||||
// Searched through the entire thing
|
||||
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->state = 1;
|
||||
|
||||
// TODO check for key length
|
||||
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
|
||||
int urmomRemove(const urmom_desc_t* desc, const char *key) {
|
||||
const int index = urmomFind(desc, key);
|
||||
if (index >= 0)
|
||||
urmomDeleteByIndex(desc, index);
|
||||
urmomRemoveByIndex(desc, 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;
|
||||
urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index);
|
||||
|
||||
|
|
|
@ -40,9 +40,13 @@ void urmomInit(const urmom_desc_t* desc);
|
|||
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.
|
||||
int urmomInsert(const urmom_desc_t* desc, const char *key);
|
||||
|
||||
void urmomDeleteByIndex(const urmom_desc_t* desc, int index);
|
||||
typedef struct urmom_insert_s {
|
||||
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
|
||||
int urmomRemove(const urmom_desc_t* desc, const char *key);
|
||||
|
||||
void urmomRemoveByIndex(const urmom_desc_t* desc, int index);
|
||||
|
|
|
@ -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 ) {
|
||||
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 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 = {
|
||||
.debug_name = tex->name,
|
||||
.debug_name = TEX_NAME(tex),
|
||||
.width = header->pixelWidth,
|
||||
.height = header->pixelHeight,
|
||||
.mips = header->levelCount,
|
||||
|
@ -373,13 +373,13 @@ static qboolean uploadTexture(int index, vk_texture_t *tex, rgbdata_t *const *co
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!validatePicLayers(tex->name, layers, num_layers))
|
||||
if (!validatePicLayers(TEX_NAME(tex), layers, num_layers))
|
||||
return false;
|
||||
|
||||
tex->width = layers[0]->width;
|
||||
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)
|
||||
// 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 = {
|
||||
.debug_name = tex->name,
|
||||
.debug_name = TEX_NAME(tex),
|
||||
.width = tex->width,
|
||||
.height = tex->height,
|
||||
.mips = mipCount,
|
||||
|
@ -462,6 +462,7 @@ void R_VkTextureDestroy( int index, vk_texture_t *tex ) {
|
|||
setDescriptorSet(index, tex, kColorspaceNative);
|
||||
|
||||
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 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) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "r_textures.h"
|
||||
|
||||
#include "vk_core.h"
|
||||
#include "vk_image.h"
|
||||
#include "vk_const.h"
|
||||
|
||||
#include "unordered_roadmap.h"
|
||||
|
||||
typedef struct vk_texture_s
|
||||
{
|
||||
char name[256];
|
||||
urmom_header_t hdr_;
|
||||
|
||||
//char name[256];
|
||||
|
||||
int width, height;
|
||||
uint32_t flags;
|
||||
|
@ -19,17 +22,14 @@ typedef struct vk_texture_s
|
|||
VkDescriptorSet descriptor_unorm;
|
||||
} vk;
|
||||
|
||||
// Internals for hash table
|
||||
uint texnum;
|
||||
uint hashValue;
|
||||
struct vk_texture_s *nextHash;
|
||||
|
||||
int refcount;
|
||||
|
||||
// TODO "cache" eviction
|
||||
// int used_maps_ago;
|
||||
} vk_texture_t;
|
||||
|
||||
#define TEX_NAME(tex) ((tex)->hdr_.key)
|
||||
|
||||
typedef enum {
|
||||
kColorspaceNative,
|
||||
kColorspaceLinear,
|
||||
|
|
Loading…
Reference in New Issue