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 "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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue