Merge pull request #612 from w23/texture-storage

Improve texture storage and lookup

- [x] Fix #594 
  - [x] Free engine textures
  - [x] Fixup descriptor sets
  - [x] Fix PBR leaks
    - [x] texture refcounts
      - [x] acquire/release textures in materials
- [x] Done #210 to separate refcount-aware material loading from refcount-unaware ref_interface_t
- [x] Done #602
- [x] #601
- [x] Fixes #617
- [x] кто украл скайбокс?! -- повар украл скайбокс
- [x] Convert blue noise to 3D texture
- [x] fixes #613
This commit is contained in:
Ivan Avdeev 2023-10-31 08:49:18 -07:00 committed by GitHub
commit f1c8b3ef2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 2522 additions and 1413 deletions

View File

@ -41,7 +41,7 @@ void R_GetTextureParms( int *w, int *h, int texnum );
#define REF_GET_PARM( parm, arg ) ref.dllFuncs.RefGetParm( (parm), (arg) )
#define GL_LoadTextureInternal( name, pic, flags ) ref.dllFuncs.GL_LoadTextureFromBuffer( (name), (pic), (flags), false )
#define GL_UpdateTextureInternal( name, pic, flags ) ref.dllFuncs.GL_LoadTextureFromBuffer( (name), (pic), (flags), true )
#define R_GetBuiltinTexture( name ) ref.dllFuncs.GL_LoadTexture( (name), 0, 0, 0 )
#define R_GetBuiltinTexture( name ) ref.dllFuncs.GL_FindTexture( (name) )
void GL_RenderFrame( const struct ref_viewpass_s *rvp );

View File

@ -635,3 +635,48 @@ For multiple replacements:
- mat_id
- name_to_material[] -- string "name" to mat_id
- hash table of some sorts
# 2023-10-16 E313
## Pre-next:
- validation crash
## Next:
- KTX2 PR against upstream
- texture leaks
- better texture storage
- hash map
- texture lifetimes/refcounts
- texture deletion
- mass (for single device wait idle)
# 2023-10-17 E314
- [x] imagelib/ktx2 PR to upstream
1. [x] Make a vulkan branch with the latest upstream merged in
2. [x] Make another branch `upstream-ktx2` from upstream/master with imagelib changes hand-picked
3. [x] Make a PR against upstream with ktx2
4. [x] Make a PR against vulkan with recentmost upstream
- [x] Contemplate texture storage
# 2023-10-19 E315
Tried refcounts. They only break things, many textures get released prematurely.
Hunch: need to split external/refapi refcount-unaware functionality and hash map into two things:
- old name->gl_texturenum table that is refcount-unaware
- new name->vk.image refcount-aware table and api
# 2023-10-20 E316
## Texture mgmt refcount impedance mismatch: losing textures on changelevel
1. ref_interface_t api is refcount-oblivious: it creates and destroys textures directly. Can't really update refcounts in these calls because they are not balanced at all. Can potentially call Load on the same texture twice, and then delete it only once. (Can it delete the same texture multiple times? Probably not -- need index, which *SHOULD* be inaccessible after the first delte by the API logic -- this is broken now with refcounts)
2. Sequence of events:
1. Changlevel initiated
2. Textures for the old map are deleted using ref_interface api
- mostly us in ref_vk (so we can adjust), but there are a few possible calls from the engine and game.dll
- brings refcount down to "1" (many textures are still referenced from materials)
3. Texture for the new map are created using ref_interface api
- There are common textures that weren't deleted due to being referenced by materials, so they are considered being uploaded already.
- ref_interface_t is refcount-oblivious, so refcounts are not updated, i.e. remaining =1.
4. ref_vk finally notices the changelevel, and starts reloading materials.
- goes through the list of all old materials and releases all the textures
- old textures (but which should've been loaded for the new map too) with refcount=1 are deleted
- ;_;

View File

@ -1,3 +1,71 @@
# 2023-10-31 E322
- [x] load png blue noise files
- [-] translucent animated thing -> needs shader rework
- [x] massage texture code
- [x] single return/goto cleanup
- [-] pass args via structs? -> not necessary
- [-] collapse texture uploading into a single function -> not necessary, they are different enough
- [ ] merge materials PR
# 2023-10-30 E321
- [x] missing skybox
- [x] explicitly free default textures; and complain about any leftovers
- [x] use the new hash table in materials too, remove dummy textures
- [x] why are there references to \*unused
- [ ] restore blue noise
- [x] vk_texture_t blue_noise; 3d texture
- [x] separate binding similar to skybox in vk_rtx.c and shaders
- [x] patch shader function
- [ ] load 64xpngs into a single big pic
# 2023-10-27 E320
- [x] fix windows build
- [x] track texture visibility for ref_api via flag and refcounts
- [ ] devmem assert, not all textures are destroyed in wagonchik
- [ ] new material names+fixme => move to material hash table
- [x] preallocated default textures
- [x] check urmom stats after a few different changelevels
- [x] COUNT(IS_DELETED)
- [x] clusters size histogram
- [x] silence logs
- [x] "accessing empty texture"
- [x] "found existing texture"
- [x] check mips
# 2023-10-26 E319
- [x] fix pbr materials disappearing
- [x] fix surface lights
- [ ] pbr/material refcount leaks
- [ ] track texture visibility for ref_api
- [x] handle existing image on texture upload
- [x] sanely recreate
- [x] reuse if possible
- [x] case insensitive hash table
# 2023-10-24 E318
- [ ] use new hashmap for textures
- [x] use vk_texure array directly as open addressing hash table
- [x] Completely hide `struct vk_texture`
- [x] just try
- [x] texture indexes are no longer consecutive
- [ ] blue noise texture breaks => make it a separate (3d) thing
- [ ] index=0 is now valid
- [x] I. mark 0 as occupied to avoid allocating it
- [ ] II. Increase all returned indexes by 1. Then dec it back wherever it is passed back
- (SAD): cannot make builtin textures have stable indexes anymore
# E313
## Pre-next:
- validation crash
## Next:
- KTX2 PR against upstream
- texture leaks
- better texture storage
- hash map
- texture lifetimes/refcounts
- texture deletion
- mass (for single device wait idle)
# Programmable render
- [ ] what if new meatpipe has different image format for a creatable image?
- [ ] implicit dependency tracking. pass defines:

View File

@ -160,7 +160,10 @@ static int splitBlockAt(pool_t *blocks, int index, alo_size_t at) {
alo_block_t aloPoolAllocate(struct alo_pool_s* pool, alo_size_t size, alo_size_t alignment) {
alo_block_t ret = {.offset = ALO_ALLOC_FAILED};
block_t *b;
ASSERT(size > 0);
alignment = alignment > pool->min_alignment ? alignment : pool->min_alignment;
for (int i = pool->first_block; i >= 0; i = b->next) {
b = poolGet(&pool->blocks, i);
if (b->flags != BlockFlag_Empty)

View File

@ -83,11 +83,11 @@
}
{
"_xvk_surface_id" "3728 3740 3771 3783" // ~SPOTRED
"_xvk_texture" "+A~GENERIC86B" // red->green
"_xvk_material" "+A~GENERIC86B" // red->green
}
{
"_xvk_surface_id" "3722 3734 3765 3777" // +A~GENERIC86B
"_xvk_texture" "~SPOTRED" // green->red
"_xvk_material" "~SPOTRED" // green->red
}

View File

@ -22,7 +22,7 @@
//{ // testing
//"_xvk_surface_id" "980 975 872 881 999 885 886 1883 1852 1763 1709 1723 1724 1750 1728" // !TOXICGRN2 20 255 0 350
//"_xvk_texture" ""
//"_xvk_material" ""
//}

View File

@ -25,7 +25,7 @@
// mirror in toilet
{
"_xvk_surface_id" "2057"
"_xvk_texture" "mirror"
"_xvk_material" "mirror"
}

View File

@ -32,7 +32,7 @@
{ // TODO: animate texture
"_xvk_surface_id" "1183" // +0~DRKMTLS1 205 0 0 6000
"_light" "205 0 0 10000"
//"_xvk_texture" "RED1_ANIMATE"
//"_xvk_material" "RED1_ANIMATE"
}
{
"_xvk_ent_id" "55 54 53 52 51" // remove hack lights entity

View File

@ -13,5 +13,5 @@
// mirror in toilet
{
"_xvk_surface_id" "1936 1934 1933"
"_xvk_texture" "mirror_broken"
"_xvk_material" "mirror_broken"
}

View File

@ -5,7 +5,7 @@
{ // TODO: animate texture
"_xvk_surface_id" "3391 3407" // +0~FIFTS_LGHT4 160 170 220 4000
"_light" "160 170 220 5000"
//"_xvk_texture" "WHITE1_ANIMATE"
//"_xvk_material" "WHITE1_ANIMATE"
}
// section 1

View File

@ -48,7 +48,7 @@
{
"_xvk_surface_id" "4592 4593 4594 4591 4589" // remove additive "god rays" fade2
"_xvk_texture" ""
"_xvk_material" ""
}
// section 4
@ -103,47 +103,47 @@
// fix wrong textures with texture coordinates
{
"_xvk_surface_id" "2363 2352 2351 2386 2389 2562 1002 1003 1013 1014"
"_xvk_texture" "crete4_flr03"
"_xvk_material" "crete4_flr03"
"_xvk_tex_offset" "20 -15.5"
"_xvk_tex_scale" "0.5 1"
}
{ // i tak soydet
"_xvk_surface_id" "2362"
"_xvk_texture" "crete4_flr03"
"_xvk_material" "crete4_flr03"
"_xvk_tex_offset" "10 16"
"_xvk_tex_scale" "0.5 1"
}
{ // i tak soydet
"_xvk_surface_id" "2563"
"_xvk_texture" "crete4_flr03"
"_xvk_material" "crete4_flr03"
"_xvk_tex_offset" "10 -15.5"
"_xvk_tex_scale" "0.5 1"
}
{
"_xvk_surface_id" "999" // LITEPANEL1
"_xvk_texture" "+ALAB1_W6"
"_xvk_material" "+ALAB1_W6"
"_light" "0 0 0 0"
"_xvk_tex_offset" "24 1"
"_xvk_tex_scale" "2.5 0.3" // TODO: rotate at 90
}
{
"_xvk_surface_id" "1010" // LITEPANEL1
"_xvk_texture" "+0LAB1_W6"
"_xvk_material" "+0LAB1_W6"
"_light" "255 255 255 4000"
"_xvk_tex_offset" "24 7"
"_xvk_tex_scale" "2.5 0.3" // TODO: rotate at 90
}
{
"_xvk_surface_id" "975 2354" // +0~FIFTS_LGHT01
"_xvk_texture" "+0~FIFTIES_LGT2"
"_xvk_material" "+0~FIFTIES_LGT2"
"_light" "255 255 255 3000"
"_xvk_tex_offset" "42 20"
"_xvk_tex_scale" "2 1.2"
}
{
"_xvk_surface_id" "974 2357" // +0~FIFTS_LGHT01
"_xvk_texture" "+0~FIFTIES_LGT2"
"_xvk_material" "+0~FIFTIES_LGT2"
"_light" "255 255 255 3000"
"_xvk_tex_offset" "42 -18"
"_xvk_tex_scale" "2 1.2"
@ -157,14 +157,14 @@
}
{
"_xvk_surface_id" "796 795 807 800 809 808 805 801 796 780"
"_xvk_texture" "generic_metal1" // TODO: texture -> material
"_xvk_material" "generic_metal1" // TODO: texture -> material
}
{
"_xvk_smoothing_group" "766 765 772 773 777 776 768 769"
}
{
"_xvk_surface_id" "766 765 772 773 777 776 768 769"
"_xvk_texture" "generic_metal1" // TODO: texture -> material
"_xvk_material" "generic_metal1" // TODO: texture -> material
}
{

View File

@ -23,7 +23,7 @@
{
"_xvk_surface_id" "2412" // generic88a
//"_xvk_texture" "black" // fix texture
//"_xvk_material" "black" // fix texture
"_light" "0 0 0 0"
}

View File

@ -61,7 +61,7 @@
//{ // TODO: fix 2 side texture coordinates
//"_xvk_surface_id" "7011 7010" // {gratestep2
//"_xvk_texture" "" // remove broken texture
//"_xvk_material" "" // remove broken texture
//}
{ // fix 2 side texture coordinates

View File

@ -4,7 +4,7 @@
}
//{
//"_xvk_surface_id" "3875 3874" // BLACK
//"_xvk_texture" "c1a3yellow"
//"_xvk_material" "c1a3yellow"
//}
// alarm lights

View File

@ -1,7 +1,7 @@
#include "camera.h"
#include "vk_math.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_brush.h"
#include "vk_light.h"
@ -65,14 +65,14 @@ void XVK_CameraDebugPrintCenterEntity( void ) {
if (surf && ent && ent->model && ent->model->surfaces) {
const int surface_index = surf - ent->model->surfaces;
const texture_t *current_tex = R_TextureAnimation(ent, surf, NULL);
const texture_t *current_tex = R_TextureAnimation(ent, surf);
const int tex_id = current_tex->gl_texturenum;
const vk_texture_t* const texture = findTexture( tex_id );
const char *const tex_name = R_TextureGetNameByIndex( tex_id );
const texture_t *tex = surf->texinfo->texture;
p += Q_snprintf(p, end - p,
"surface index: %d; texture: %s(%d)\n",
surface_index, texture ? texture->name : "NONE", tex_id
surface_index, tex_name ? tex_name : "NONE", tex_id
);
if (tex->anim_total > 0 && tex->anim_next) {
@ -80,9 +80,9 @@ void XVK_CameraDebugPrintCenterEntity( void ) {
p += Q_snprintf(p, end - p,
"anim textures chain (%d):\n", tex->anim_total);
for (int i = 0; i < tex->anim_total && tex; ++i) {
const vk_texture_t *vkt = findTexture(tex->gl_texturenum);
const char* const texname = R_TextureGetNameByIndex(tex->gl_texturenum);
p += Q_snprintf(p, end - p,
"%d: %s(%d)%s\n", i, vkt ? vkt->name : "NONE", tex->gl_texturenum, tex == current_tex ? " <-" : " ");
"%d: %s(%d)%s\n", i, texname ? texname : "NONE", tex->gl_texturenum, tex == current_tex ? " <-" : " ");
tex = tex->anim_next;
}
}

1044
ref/vk/r_textures.c Normal file

File diff suppressed because it is too large Load Diff

69
ref/vk/r_textures.h Normal file
View File

@ -0,0 +1,69 @@
#pragma once
#include "const.h" // required for com_model.h, ref_api.h
#include "cvardef.h" // required for ref_api.h
#include "com_model.h" // required for ref_api.h
#include "ref_api.h" // texFlags_t
#define MAX_LIGHTMAPS 256
typedef struct vk_textures_global_s
{
// TODO Fix these at compile time statically, akin to BLUE_NOISE_TEXTURE_ID
int defaultTexture; // use for bad textures
int particleTexture;
int whiteTexture;
int grayTexture;
int blackTexture;
int solidskyTexture; // quake1 solid-sky layer
int alphaskyTexture; // quake1 alpha-sky layer
int lightmapTextures[MAX_LIGHTMAPS];
int dlightTexture; // custom dlight texture
int cinTexture; // cinematic texture
// TODO wire it up for ref_interface_t return
qboolean fCustomSkybox;
} vk_textures_global_t;
// TODO rename this consistently
extern vk_textures_global_t tglob;
qboolean R_TexturesInit( void );
void R_TexturesShutdown( void );
////////////////////////////////////////////////////////////
// Ref interface functions, exported
// TODO mark names somehow, ie. R_TextureApi... ?
int R_TextureFindByName( const char *name );
const char* R_TextureGetNameByIndex( unsigned int texnum );
void R_TextureSetupSky( const char *skyboxname );
int R_TextureUploadFromFile( const char *name, const byte *buf, size_t size, int flags );
int R_TextureUploadFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update_only );
void R_TextureFree( unsigned int texnum );
int R_TexturesGetParm( int parm, int arg );
////////////////////////////////////////////////////////////
// Extra functions used in ref_vk
void R_TextureAcquire( unsigned int texnum );
void R_TextureRelease( unsigned int texnum );
typedef enum {
kColorspaceNative,
kColorspaceLinear,
kColorspaceGamma,
} colorspace_hint_e;
int R_TextureUploadFromFileExAcquire( const char *filename, colorspace_hint_e colorspace, qboolean force_reload );
int R_TextureFindByNameF( const char *fmt, ...);
// Tries to find a texture by its short name
// Full names depend on map name, wad name, etc. This function tries them all.
// Returns -1 if not found
int R_TextureFindByNameLike( const char *texture_name );
struct vk_texture_s;
struct vk_texture_s *R_TextureGetByIndex( uint index );

View File

@ -1,20 +1,14 @@
#ifndef BLUENOISE_H_INCLUDED
#define BLUENOISE_H_INCLUDED
// Depends on uniform sampler2D textures[MAX_TEXTURES] binding being defined
// This is the same hardcoded value as in vk_textures.h
// Please keep them in sync onegai uwu
// TODO:
// - make bluenoise texture a separate binding, not part of textures[] array
// - make it a 3D texture
#define BLUE_NOISE_TEXTURE_BEGIN 7
// Depends on uniform sampler3D blue_noise_texture binding being defined
// Also see vk_textures.h, keep in sync, etc etc
#define BLUE_NOISE_SIZE 64
vec4 blueNoise(ivec3 v) {
v %= BLUE_NOISE_SIZE;
return texelFetch(textures[BLUE_NOISE_TEXTURE_BEGIN+v.z], v.xy, 0);
ivec3 size = textureSize(blue_noise_texture, 0);
return texelFetch(blue_noise_texture, v % size, 0);
}
#endif // ifndef BLUENOISE_H_INCLUDED

View File

@ -36,9 +36,10 @@ layout(set = 0, binding = 15, rgba16f) uniform image2D prev_temporal_diffuse;
layout(set = 0, binding = 16, rgba16f) uniform image2D out_temporal_specular;
layout(set = 0, binding = 17, rgba16f) uniform image2D prev_temporal_specular;
//#define DEBUG_NOISE
#ifdef DEBUG_NOISE
layout(set = 0, binding = 18) uniform sampler2D textures[MAX_TEXTURES];
include "bluenoise.glsl"
layout(set = 0, binding = 18) uniform sampler3D blue_noise_texture;
#include "bluenoise.glsl"
#endif
//layout(set = 0, binding = 19) uniform sampler2D textures[MAX_TEXTURES];

View File

@ -0,0 +1,240 @@
#include "../unordered_roadmap.h"
#define URMOM_TEST
#include "../unordered_roadmap.c"
#define LOG(msg, ...) \
fprintf(stderr, "%s:%d: " msg "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define CHECK_EQUAL_I(a, b) \
do { \
const int ar = (a), br = (b); \
if (ar != br) { \
LOG("CHECK_EQUAL_I("#a", "#b") failed: %d != %d", ar, br); \
return 0; \
} \
} while (0)
#define CHECK_EQUAL_S(a, b) \
do { \
const char *ar = (a), *br = (b); \
if (strcmp(ar, br) != 0) { \
LOG("CHECK_EQUAL_S("#a", "#b") failed: \"%s\" != \"%s\"", ar, br); \
return 0; \
} \
} while (0)
#define CHECK_NOT_EQUAL_I(a, b) \
do { \
const int ar = (a), br = (b); \
if (ar == br) { \
LOG("CHECK_NOT_EQUAL_I("#a", "#b") failed: %d == %d", ar, br); \
return 0; \
} \
} while (0)
typedef struct {
urmom_header_t hdr_;
int i;
float f;
} item_t;
#define PREAMBLE(N, type_) \
item_t items[N]; \
const urmom_desc_t desc = { \
.array = items, \
.count = COUNTOF(items), \
.item_size = sizeof(item_t), \
.type = type_, \
}; \
urmomInit(&desc)
static int test_insert_find_remove( void ) {
PREAMBLE(4, kUrmomString);
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.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.index);
CHECK_EQUAL_I(items[i.index].hdr_.key[0], '\0');
const int not_found = urmomFind(&desc, "bidonchik");
CHECK_EQUAL_I(not_found, -1);
return 1;
}
static int test_find_nonexistent( void ) {
PREAMBLE(4, kUrmomString);
const int found = urmomFind(&desc, "kishochki");
CHECK_EQUAL_I(found, -1);
return 1;
}
static int test_insert_find_many( void ) {
PREAMBLE(4, kUrmomString);
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 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.index);
CHECK_EQUAL_I(b_found, b.index);
return 1;
}
static int test_overflow( void ) {
PREAMBLE(4, kUrmomString);
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 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 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 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 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.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 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;
}
// Assumes FNV-1a
static int test_hash_collision( void ) {
PREAMBLE(4, kUrmomString);
const urmom_insert_t a = urmomInsert(&desc, "costarring");
CHECK_NOT_EQUAL_I(a.index, -1);
CHECK_EQUAL_I(a.created, 1);
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.index].hdr_.hash, items[b.index].hdr_.hash);
const int a_found = urmomFind(&desc, "costarring");
CHECK_EQUAL_I(a_found, a.index);
const int b_found = urmomFind(&desc, "liquid");
CHECK_EQUAL_I(b_found, b.index);
return 1;
}
static int test_insert_find_remove_insensitive( void ) {
PREAMBLE(4, kUrmomStringInsensitive);
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.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.index);
CHECK_EQUAL_I(items[i.index].hdr_.key[0], '\0');
const int not_found = urmomFind(&desc, "bidonchik");
CHECK_EQUAL_I(not_found, -1);
return 1;
}
static int test_fail( void ) {
//CHECK_EQUAL_S("sapogi", "tapki");
return 1;
}
#define LIST_TESTS(X) \
X(test_insert_find_remove) \
X(test_find_nonexistent) \
X(test_insert_find_many) \
X(test_hash_collision) \
X(test_insert_find_remove_insensitive) \
X(test_fail) \
int main( void ) {
int retval = 0;
#define X(f) \
do { \
fprintf(stderr, "Running " #f "...\n"); \
const int result = f(); \
fprintf(stderr, #f " => %s\n", result == 0 ? "FAIL" : "OK" ); \
if (!result) \
++retval;\
} while (0);
LIST_TESTS(X)
#undef X
return retval;
}

184
ref/vk/unordered_roadmap.c Normal file
View File

@ -0,0 +1,184 @@
#include "unordered_roadmap.h"
#ifndef URMOM_TEST
#include "vk_common.h"
#include "vk_logs.h"
#else
#include <string.h>
#include <stdio.h>
#include <assert.h>
#define ERR(msg, ...) fprintf(stderr, msg, ##__VA_ARGS__)
#define ASSERT(...) assert(__VA_ARGS__)
#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
#endif
#if defined(_WIN32) && !defined(strcasecmp)
#define strcasecmp _stricmp
#endif
static uint32_t hash32FNV1aStr(const char *str) {
static const uint32_t fnv_offset_basis = 0x811c9dc5u;
static const uint32_t fnv_prime = 0x01000193u;
uint32_t hash = fnv_offset_basis;
while (*str) {
hash ^= *str;
hash *= fnv_prime;
++str;
}
return hash;
}
static uint32_t hash32FNV1aStrI(const char *str) {
static const uint32_t fnv_offset_basis = 0x811c9dc5u;
static const uint32_t fnv_prime = 0x01000193u;
uint32_t hash = fnv_offset_basis;
while (*str) {
hash ^= (*str & 0xdf);
hash *= fnv_prime;
++str;
}
return hash;
}
// Sets all items to empty
void urmomInit(const urmom_desc_t* desc) {
char *ptr = desc->array;
// Make sure that count is 2^N
ASSERT((desc->count & (desc->count - 1)) == 0);
for (int i = 0; i < desc->count; ++i) {
urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * i);
hdr->state = 0;
hdr->hash = 0;
}
}
static uint32_t hashKey(urmom_type_t type, const char *key) {
uint32_t hash;
switch (type) {
case kUrmomString:
hash = hash32FNV1aStr(key);
break;
case kUrmomStringInsensitive:
hash = hash32FNV1aStrI(key);
break;
default:
ASSERT(!"Invalid hash table key type");
}
return hash & 0x7fffffffu;
}
static int sameKey(urmom_type_t type, const char *key1, const char *key2) {
switch (type) {
case kUrmomString:
return strcmp(key1, key2) == 0;
case kUrmomStringInsensitive:
return strcasecmp(key1, key2) == 0;
default:
ASSERT(!"Invalid hash table key type");
}
return 0;
}
// Returns index of the element with the key if found, -1 otherwise
int urmomFind(const urmom_desc_t* desc, const char* key) {
const char *ptr = desc->array;
const uint32_t hash = hashKey(desc->type, key);
const uint32_t mask = (desc->count - 1);
const int start_index = hash & mask;
for (int index = start_index;;) {
const urmom_header_t *hdr = (urmom_header_t*)(ptr + desc->item_size * index);
if (URMOM_IS_OCCUPIED(*hdr)) {
if (hdr->hash == hash && sameKey(desc->type, key, hdr->key))
return index;
} else if (URMOM_IS_EMPTY(*hdr))
// Reached the end of non-empty chain, not found
break;
// No match ;_;, check the next one
index = (index + 1) & mask;
// Searched through the entire thing
if (index == start_index)
break;
}
return -1;
}
// Returns index of the element either found or empty slot where this could be inserted. If full, -1.
urmom_insert_t urmomInsert(const urmom_desc_t* desc, const char *key) {
char *ptr = desc->array;
const uint32_t hash = hashKey(desc->type, key);
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 && sameKey(desc->type, key, hdr->key))
// Return existing item
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
if (URMOM_IS_EMPTY(*hdr))
break;
}
index = (index + 1) & mask;
// Searched through the entire thing
if (index == start_index)
break;
}
// 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 (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)
urmomRemoveByIndex(desc, index);
return 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);
if (!URMOM_IS_OCCUPIED(*hdr)) {
ERR("Hashmap=%p(is=%d, n=%d): lot %d is not occupied", desc->array, desc->item_size, desc->count, index);
return;
}
// Mark it as deleted
// TODO when can we mark it as empty? For linear search we can do so if the next one is empty
hdr->state = 0; // not occupied
hdr->hash = 1; // deleted, not empty
hdr->key[0] = '\0';
}

View File

@ -0,0 +1,68 @@
#pragma once
#include <stdint.h>
#define MAX_KEY_STRING_LENGTH 256
// URMOM = Unordered RoadMap Open addressiMg
// Open-addressed hash table item header
typedef struct urmom_header_s {
// state == 1, hash == 0 -- item with hash==0
// state == 0, hash != 0 -- deleted
// state == 0, hash == 0 -- empty
uint32_t state:1;
uint32_t hash:31;
char key[MAX_KEY_STRING_LENGTH];
} urmom_header_t;
#define URMOM_IS_OCCUPIED(hdr) ((hdr).state != 0)
#define URMOM_IS_EMPTY(hdr) ((hdr).state == 0 && (hdr).hash == 0)
#define URMOM_IS_DELETED(hdr) ((hdr).state == 0 && (hdr).hash != 0)
// TODO:
// - rename this to key type
// - allow passing key not as const char*, but as string_view
// - (or even just void*+size, which would almost make it universal)
typedef enum {
kUrmomString,
kUrmomStringInsensitive,
} urmom_type_t;
typedef struct urmom_desc_s {
// Pointer to the beginning of the array of items.
// Each item is a struct that has urmom_header_t as its first field
void *array;
// Array item size, including the urmom_header_t
uint32_t item_size;
// Maximum number of items in the array
uint32_t count;
urmom_type_t type;
} urmom_desc_t;
// Sets all items to empty
void urmomInit(const urmom_desc_t* desc);
// Returns index of the element with the key if found, -1 otherwise
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.
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);
// TODO erase IS_DELETED tails
// void urmomCleanup()
// TODO optimize storage: collapse non-tail IS_DELETED sequences. Items will have new placement, so all indexes will be stale

View File

@ -3,7 +3,7 @@
#include "camera.h"
#include "vk_render.h"
#include "vk_geometry.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_sprite.h"
#include "vk_scene.h"
#include "vk_math.h"

View File

@ -6,7 +6,7 @@
#include "vk_pipeline.h"
#include "vk_framectl.h"
#include "vk_math.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_lightmap.h"
#include "vk_scene.h"
#include "vk_render.h"
@ -404,8 +404,8 @@ static void fillWaterSurfaces( const cl_entity_t *ent, vk_brush_model_t *bmodel,
static rt_light_add_polygon_t loadPolyLight(const model_t *mod, const int surface_index, const msurface_t *surf, const vec3_t emissive);
static qboolean isSurfaceAnimated( const msurface_t *s, const struct texture_s *base_override ) {
const texture_t *base = base_override ? base_override : s->texinfo->texture;
static qboolean isSurfaceAnimated( const msurface_t *s ) {
const texture_t *base = s->texinfo->texture;
/* FIXME don't have ent here, need to check both explicitly
if( ent && ent->curstate.frame ) {
@ -483,8 +483,8 @@ static brush_surface_type_e getSurfaceType( const msurface_t *surf, int i ) {
return BrushSurface_Hidden;
}
const struct texture_s *texture_override = patch_surface ? patch_surface->tex : NULL;
if (isSurfaceAnimated(surf, texture_override)) {
const qboolean patched_material = patch_surface && !!(patch_surface->flags & Patch_Surface_Material);
if (!patched_material && isSurfaceAnimated(surf)) {
return BrushSurface_Animated;
}
@ -534,7 +534,7 @@ static qboolean brushCreateWaterModel(const model_t *mod, vk_brush_model_t *bmod
return true;
}
material_mode_e brushMaterialModeForRenderType(vk_render_type_e render_type) {
static material_mode_e brushMaterialModeForRenderType(vk_render_type_e render_type) {
switch (render_type) {
case kVkRenderTypeSolid:
return kMaterialMode_Opaque;
@ -582,12 +582,13 @@ static void brushDrawWater(vk_brush_model_t *bmodel, const cl_entity_t *ent, int
APROF_SCOPE_END(brush_draw_water);
}
// FIXME use this
#if 0
// TODO use this
static void computeConveyorSpeed(const color24 rendercolor, int tex_index, vec2_t speed) {
float sy, cy;
float flConveyorSpeed = 0.0f;
float flRate, flAngle;
vk_texture_t *texture = findTexture( tex_index );
vk_texture_t *texture = R_TextureGetByIndex( tex_index );
//gl_texture_t *texture;
// FIXME
@ -610,6 +611,7 @@ static void computeConveyorSpeed(const color24 rendercolor, int tex_index, vec2_
speed[0] = cy * flRate;
speed[1] = sy * flRate;
}
#endif
/*
===============
@ -618,9 +620,9 @@ R_TextureAnimation
Returns the proper texture for a given time and surface
===============
*/
const texture_t *R_TextureAnimation( const cl_entity_t *ent, const msurface_t *s, const struct texture_s *base_override )
const texture_t *R_TextureAnimation( const cl_entity_t *ent, const msurface_t *s )
{
const texture_t *base = base_override ? base_override : s->texinfo->texture;
const texture_t *base = s->texinfo->texture;
int count, reletive;
if( ent && ent->curstate.frame )
@ -644,9 +646,10 @@ const texture_t *R_TextureAnimation( const cl_entity_t *ent, const msurface_t *s
int speed;
// Quake1 textures uses 10 frames per second
if( FBitSet( findTexture( base->gl_texturenum )->flags, TF_QUAKEPAL ))
/* TODO
if( FBitSet( R_TextureGetByIndex( base->gl_texturenum )->flags, TF_QUAKEPAL ))
speed = 10;
else speed = 20;
else */ speed = 20;
reletive = (int)(gpGlobals->time * speed) % base->anim_total;
}
@ -742,8 +745,7 @@ void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, co
const xvk_patch_surface_t *const patch_surface = R_VkPatchGetSurface(surface_index);
// Optionally patch by texture_s pointer and run animations
const struct texture_s *texture_override = patch_surface ? patch_surface->tex : NULL;
const texture_t *t = R_TextureAnimation(ent, geom->surf_deprecate, texture_override);
const texture_t *t = R_TextureAnimation(ent, geom->surf_deprecate);
const int new_tex_id = t->gl_texturenum;
if (new_tex_id >= 0 && new_tex_id != geom->ye_olde_texture) {
@ -840,16 +842,11 @@ static void getSurfaceNormal( const msurface_t *surf, vec3_t out_normal) {
VectorCopy( surf->plane->normal, out_normal );
// TODO scale normal by area -- bigger surfaces should have bigger impact
// NOTE scaling normal by area might be totally incorrect in many circumstances
// The more corect logic there is way more difficult
//VectorScale(normal, surf->plane.
}
static int getSurfaceTexture(const msurface_t *surf, int surface_index) {
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
if (psurf && psurf->tex_id >= 0)
return psurf->tex_id;
return surf->texinfo->texture->gl_texturenum;
}
static qboolean shouldSmoothLinkSurfaces(const model_t* mod, qboolean smooth_entire_model, int surf1, int surf2) {
//return Q_min(surf1, surf2) == 741 && Q_max(surf1, surf2) == 743;
@ -884,10 +881,13 @@ static qboolean shouldSmoothLinkSurfaces(const model_t* mod, qboolean smooth_ent
}
// Do not join surfaces with different textures. Assume they belong to different objects.
const int t1 = getSurfaceTexture(mod->surfaces + surf1, surf1);
const int t2 = getSurfaceTexture(mod->surfaces + surf2, surf2);
if (t1 != t2)
return false;
{
// Should we also check texture/material patches too to filter out pairs which originally had
// same textures, but with patches do not?
if (mod->surfaces[surf1].texinfo->texture->gl_texturenum
!= mod->surfaces[surf2].texinfo->texture->gl_texturenum)
return false;
}
vec3_t n1, n2;
getSurfaceNormal(mod->surfaces + surf1, n1);
@ -1091,8 +1091,6 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
// TODO this patching should probably override entity patching below
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
if (psurf && psurf->tex_id >= 0)
tex_id = psurf->tex_id;
const brush_surface_type_e type = getSurfaceType(surf, surface_index);
switch (type) {
@ -1119,9 +1117,14 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
}
model_geometry->ye_olde_texture = orig_tex_id;
qboolean material_assigned = false;
if (entity_patch) {
if (psurf && (psurf->flags & Patch_Surface_Material)) {
model_geometry->material = R_VkMaterialGetForRef(psurf->material_ref);
material_assigned = true;
}
if (!material_assigned && entity_patch) {
for (int i = 0; i < entity_patch->matmap_count; ++i) {
if (entity_patch->matmap[i].from_tex == orig_tex_id) {
model_geometry->material = R_VkMaterialGetForTexture(entity_patch->matmap[i].to_mat.index);
@ -1555,3 +1558,18 @@ void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean
INFO("Loaded %d polylights for %s model %s", emissive_surfaces_count, is_static ? "static" : "movable", mod->name);
}
}
void VK_BrushUnloadTextures( model_t *mod )
{
int i;
for( i = 0; i < mod->numtextures; i++ )
{
texture_t *tx = mod->textures[i];
if( !tx || tx->gl_texturenum == tglob.defaultTexture )
continue; // free slot
R_TextureFree( tx->gl_texturenum ); // main texture
R_TextureFree( tx->fb_texturenum ); // luma texture
}
}

View File

@ -16,6 +16,8 @@ void VK_BrushModelDestroyAll( void );
void VK_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, const matrix4x4 model );
const texture_t *R_TextureAnimation( const cl_entity_t *ent, const msurface_t *s, const struct texture_s *base_override );
const texture_t *R_TextureAnimation( const cl_entity_t *ent, const msurface_t *s );
void R_VkBrushModelCollectEmissiveSurfaces( const struct model_s *mod, qboolean is_worldmodel );
void VK_BrushUnloadTextures( model_t *mod );

View File

@ -1,7 +1,7 @@
#include "vk_core.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_overlay.h"
#include "vk_renderstate.h"
#include "vk_staging.h"
@ -786,7 +786,7 @@ qboolean R_VkInit( void )
VK_SceneInit();
initTextures();
R_TexturesInit();
// All below need render_pass
@ -833,7 +833,9 @@ void R_VkShutdown( void ) {
VK_FrameCtlShutdown();
destroyTextures();
R_VkMaterialsShutdown();
R_TexturesShutdown();
VK_PipelineShutdown();

View File

@ -2,7 +2,7 @@
#include "eiface.h" // ARRAYSIZE
descriptor_pool_t vk_desc;
descriptor_pool_t vk_desc_fixme;
qboolean VK_DescriptorInit( void )
{
@ -14,7 +14,7 @@ qboolean VK_DescriptorInit( void )
.descriptorCount = MAX_TEXTURES,
}, {
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
.descriptorCount = ARRAYSIZE(vk_desc.ubo_sets),
.descriptorCount = ARRAYSIZE(vk_desc_fixme.ubo_sets),
/*
}, {
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
@ -33,7 +33,7 @@ qboolean VK_DescriptorInit( void )
dpci.maxSets = max_desc_sets;
XVK_CHECK(vkCreateDescriptorPool(vk_core.device, &dpci, NULL, &vk_desc.pool));
XVK_CHECK(vkCreateDescriptorPool(vk_core.device, &dpci, NULL, &vk_desc_fixme.pool));
{
const int num_sets = MAX_TEXTURES;
@ -53,21 +53,21 @@ qboolean VK_DescriptorInit( void )
VkDescriptorSetLayout* tmp_layouts = Mem_Malloc(vk_core.pool, sizeof(VkDescriptorSetLayout) * num_sets);
const VkDescriptorSetAllocateInfo dsai = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = vk_desc.pool,
.descriptorPool = vk_desc_fixme.pool,
.descriptorSetCount = num_sets,
.pSetLayouts = tmp_layouts,
};
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc.one_texture_layout));
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc_fixme.one_texture_layout));
for (int i = 0; i < num_sets; ++i)
tmp_layouts[i] = vk_desc.one_texture_layout;
tmp_layouts[i] = vk_desc_fixme.one_texture_layout;
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc.sets));
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc_fixme.texture_sets));
Mem_Free(tmp_layouts);
}
{
const int num_sets = ARRAYSIZE(vk_desc.ubo_sets);
const int num_sets = ARRAYSIZE(vk_desc_fixme.ubo_sets);
// ... TODO find better place for this; this should be per-pipeline/shader
VkDescriptorSetLayoutBinding bindings[] = { {
.binding = 0,
@ -84,15 +84,15 @@ qboolean VK_DescriptorInit( void )
VkDescriptorSetLayout* tmp_layouts = Mem_Malloc(vk_core.pool, sizeof(VkDescriptorSetLayout) * num_sets);
VkDescriptorSetAllocateInfo dsai = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = vk_desc.pool,
.descriptorPool = vk_desc_fixme.pool,
.descriptorSetCount = num_sets,
.pSetLayouts = tmp_layouts,
};
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc.one_uniform_buffer_layout));
XVK_CHECK(vkCreateDescriptorSetLayout(vk_core.device, &dslci, NULL, &vk_desc_fixme.one_uniform_buffer_layout));
for (int i = 0; i < num_sets; ++i)
tmp_layouts[i] = vk_desc.one_uniform_buffer_layout;
tmp_layouts[i] = vk_desc_fixme.one_uniform_buffer_layout;
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc.ubo_sets));
XVK_CHECK(vkAllocateDescriptorSets(vk_core.device, &dsai, vk_desc_fixme.ubo_sets));
Mem_Free(tmp_layouts);
}
@ -102,9 +102,9 @@ qboolean VK_DescriptorInit( void )
void VK_DescriptorShutdown( void )
{
vkDestroyDescriptorPool(vk_core.device, vk_desc.pool, NULL);
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc.one_texture_layout, NULL);
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc.one_uniform_buffer_layout, NULL);
vkDestroyDescriptorPool(vk_core.device, vk_desc_fixme.pool, NULL);
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc_fixme.one_texture_layout, NULL);
vkDestroyDescriptorSetLayout(vk_core.device, vk_desc_fixme.one_uniform_buffer_layout, NULL);
}
void VK_DescriptorsCreate(vk_descriptors_t *desc)

View File

@ -4,16 +4,12 @@
#include "vk_const.h"
// Only used for traditional renderer
typedef struct descriptor_pool_s
{
VkDescriptorPool pool;
// TODO don't expose this, make a function to alloc desc set with given layout instead
int next_free;
//uint32_t *free_set;
// * 2 because of unorm views for trad renderer
VkDescriptorSet sets[MAX_TEXTURES * 2];
VkDescriptorSet texture_sets[MAX_TEXTURES];
VkDescriptorSetLayout one_texture_layout;
// FIXME HOW THE F
@ -21,7 +17,8 @@ typedef struct descriptor_pool_s
VkDescriptorSetLayout one_uniform_buffer_layout;
} descriptor_pool_t;
extern descriptor_pool_t vk_desc;
// FIXME: move to traditional renderer
extern descriptor_pool_t vk_desc_fixme;
qboolean VK_DescriptorInit( void );
void VK_DescriptorShutdown( void );
@ -30,7 +27,7 @@ struct xvk_image_s;
typedef union {
VkDescriptorBufferInfo buffer;
VkDescriptorImageInfo image;
VkDescriptorImageInfo *image_array;
const VkDescriptorImageInfo *image_array;
VkWriteDescriptorSetAccelerationStructureKHR accel;
const struct r_vk_image_s *image_object;
} vk_descriptor_value_t;

View File

@ -534,6 +534,7 @@ static rgbdata_t *XVK_ReadPixels( void ) {
.debug_name = "screenshot",
.width = vk_frame.width,
.height = vk_frame.height,
.depth = 1,
.mips = 1,
.layers = 1,
.format = dest_format,

View File

@ -30,6 +30,11 @@ r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create) {
VkMemoryRequirements memreq;
const qboolean is_cubemap = !!(create->flags & kVkImageFlagIsCubemap);
const qboolean is_3d = create->depth > 1;
ASSERT(create->depth > 0);
ASSERT(is_cubemap + is_3d != 2);
const VkFormat unorm_format = unormFormatFor(create->format);
const qboolean create_unorm =
@ -39,10 +44,10 @@ r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create) {
VkImageCreateInfo ici = {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.imageType = is_3d ? VK_IMAGE_TYPE_3D : VK_IMAGE_TYPE_2D,
.extent.width = create->width,
.extent.height = create->height,
.extent.depth = 1,
.extent.depth = create->depth,
.mipLevels = create->mips,
.arrayLayers = create->layers,
.format = create->format,
@ -72,7 +77,7 @@ r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create) {
VkImageViewCreateInfo ivci = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.viewType = is_cubemap ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D,
.viewType = is_cubemap ? VK_IMAGE_VIEW_TYPE_CUBE : (is_3d ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D),
.format = ici.format,
.image = image.image,
.subresourceRange.aspectMask = is_depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT,
@ -98,8 +103,10 @@ r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create) {
image.width = create->width;
image.height = create->height;
image.depth = create->depth;
image.mips = create->mips;
image.layers = create->layers;
image.flags = create->flags;
return image;
}
@ -251,6 +258,7 @@ void R_VkImageUploadBegin( r_vk_image_t *img ) {
void R_VkImageUploadSlice( r_vk_image_t *img, int layer, int mip, int size, const void *data ) {
const uint32_t width = Q_max(1, img->width >> mip);
const uint32_t height = Q_max(1, img->height >> mip);
const uint32_t depth = Q_max(1, img->depth >> mip);
const uint32_t texel_block_size = R_VkImageFormatTexelBlockSize(img->format);
const vk_staging_image_args_t staging_args = {
@ -268,7 +276,7 @@ void R_VkImageUploadSlice( r_vk_image_t *img, int layer, int mip, int size, cons
.imageExtent = (VkExtent3D){
.width = width,
.height = height,
.depth = 1,
.depth = depth,
},
},
.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,

View File

@ -11,9 +11,10 @@ typedef struct r_vk_image_s {
// Used for sRGB-γ-unaware traditional renderer
VkImageView view_unorm;
uint32_t width, height;
uint32_t width, height, depth;
int mips, layers;
VkFormat format;
uint32_t flags;
} r_vk_image_t;
enum {
@ -24,7 +25,7 @@ enum {
typedef struct {
const char *debug_name;
uint32_t width, height;
uint32_t width, height, depth;
int mips, layers;
VkFormat format;
VkImageTiling tiling;

View File

@ -1,7 +1,7 @@
#include "vk_light.h"
#include "vk_buffer.h"
#include "vk_mapents.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_lightmap.h"
#include "vk_cvar.h"
#include "vk_common.h"
@ -233,20 +233,21 @@ static qboolean loadRadData( const model_t *map, const char *fmt, ... ) {
}
// FIXME replace this with findTexturesNamedLike from vk_materials.c
// It has slightly different logic, though, and is a bit scary to change
// Try bsp texture first
tex_id = XVK_TextureLookupF("#%s:%s.mip", map->name, texture_name);
tex_id = R_TextureFindByNameF("#%s:%s.mip", map->name, texture_name);
// Try wad texture if bsp is not there
if (!tex_id && wad_name) {
tex_id = XVK_TextureLookupF("%s.wad/%s.mip", wad_name, texture_name);
tex_id = R_TextureFindByNameF("%s.wad/%s.mip", wad_name, texture_name);
}
if (!tex_id) {
const char *wad = g_map_entities.wadlist;
for (; *wad;) {
const char *const wad_end = Q_strchr(wad, ';');
tex_id = XVK_TextureLookupF("%.*s/%s.mip", wad_end - wad, wad, texture_name);
tex_id = R_TextureFindByNameF("%.*s/%s.mip", wad_end - wad, wad, texture_name);
if (tex_id)
break;
wad = wad_end + 1;

View File

@ -1,6 +1,6 @@
#include "vk_lightmap.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_cvar.h"
#include "com_strings.h"
@ -115,7 +115,7 @@ static void LM_UploadBlock( qboolean dynamic )
r_lightmap.size = r_lightmap.width * r_lightmap.height * 4;
r_lightmap.flags = IMAGE_HAS_COLOR;
r_lightmap.buffer = gl_lms.lightmap_buffer;
tglob.lightmapTextures[i] = VK_LoadTextureInternal( lmName, &r_lightmap, TF_FONT|TF_ATLAS_PAGE|TF_NOMIPMAP );
tglob.lightmapTextures[i] = R_TextureUploadFromBuffer( lmName, &r_lightmap, TF_ATLAS_PAGE|TF_NOMIPMAP|TF_CLAMP, false );
if( ++gl_lms.current_lightmap_texture == MAX_LIGHTMAPS )
gEngine.Host_Error( "AllocBlock: full\n" );
@ -227,7 +227,7 @@ void VK_UploadLightmap( void )
void VK_ClearLightmap( void )
{
for (int i = 0; i < gl_lms.current_lightmap_texture; ++i)
VK_FreeTexture(tglob.lightmapTextures[i]);
R_TextureFree(tglob.lightmapTextures[i]);
gl_lms.current_lightmap_texture = 0;
LM_InitBlock();

View File

@ -1,7 +1,7 @@
#include "vk_common.h"
#include "vk_mapents.h"
#include "vk_core.h" // TODO we need only pool from there, not the entire vulkan garbage
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_logs.h"
#include "eiface.h" // ARRAYSIZE
@ -397,7 +397,7 @@ static void readFuncAny( const entity_props_t *const props, uint32_t have_fields
static void addPatchSurface( const entity_props_t *props, uint32_t have_fields ) {
const model_t* const map = gEngine.pfnGetModelByIndex( 1 );
const int num_surfaces = map->numsurfaces;
const qboolean should_remove = (have_fields == Field__xvk_surface_id) || (have_fields & Field__xvk_texture && props->_xvk_texture[0] == '\0');
const qboolean should_remove = (have_fields == Field__xvk_surface_id) || (have_fields & Field__xvk_material && props->_xvk_material[0] == '\0');
for (int i = 0; i < props->_xvk_surface_id.num; ++i) {
const int index = props->_xvk_surface_id.values[i];
@ -412,8 +412,7 @@ static void addPatchSurface( const entity_props_t *props, uint32_t have_fields )
g_patch.surfaces_count = num_surfaces;
for (int i = 0; i < num_surfaces; ++i) {
g_patch.surfaces[i].flags = Patch_Surface_NoPatch;
g_patch.surfaces[i].tex_id = -1;
g_patch.surfaces[i].tex = NULL;
g_patch.surfaces[i].material_ref.index = -1;
}
}
@ -425,22 +424,15 @@ static void addPatchSurface( const entity_props_t *props, uint32_t have_fields )
continue;
}
if (have_fields & Field__xvk_texture) {
const int tex_id = XVK_FindTextureNamedLike( props->_xvk_texture );
DEBUG("Patch for surface %d with texture \"%s\" -> %d", index, props->_xvk_texture, tex_id);
psurf->tex_id = tex_id;
// Find texture_t for this index
for (int i = 0; i < map->numtextures; ++i) {
const texture_t* const tex = map->textures[i];
if (tex->gl_texturenum == tex_id) {
psurf->tex = tex;
psurf->tex_id = -1;
break;
}
if (have_fields & Field__xvk_material) {
const r_vk_material_ref_t mat = R_VkMaterialGetForName( props->_xvk_material );
if (mat.index >= 0) {
DEBUG("Patch for surface %d with material \"%s\" -> %d", index, props->_xvk_material, mat.index);
psurf->material_ref = mat;
psurf->flags |= Patch_Surface_Material;
} else {
ERR("Cannot patch surface %d with material \"%s\": material not found", index, props->_xvk_material);
}
psurf->flags |= Patch_Surface_Texture;
}
if (have_fields & Field__light) {
@ -457,13 +449,13 @@ static void addPatchSurface( const entity_props_t *props, uint32_t have_fields )
Vector4Copy(props->_xvk_svec, psurf->s_vec);
Vector4Copy(props->_xvk_tvec, psurf->t_vec);
psurf->flags |= Patch_Surface_STvecs;
DEBUG("Patch for surface %d: assign stvec", index);
DEBUG("Patch for surface %d: assign st_vec", index);
}
if (have_fields & Field__xvk_tex_scale) {
Vector2Copy(props->_xvk_tex_scale, psurf->tex_scale);
psurf->flags |= Patch_Surface_TexScale;
DEBUG("Patch for surface %d: assign tex scale %f %f",
DEBUG("Patch for surface %d: assign tex_scale %f %f",
index, psurf->tex_scale[0], psurf->tex_scale[1]
);
}
@ -471,7 +463,7 @@ static void addPatchSurface( const entity_props_t *props, uint32_t have_fields )
if (have_fields & Field__xvk_tex_offset) {
Vector2Copy(props->_xvk_tex_offset, psurf->tex_offset);
psurf->flags |= Patch_Surface_TexOffset;
DEBUG("Patch for surface %d: assign tex offset %f %f",
DEBUG("Patch for surface %d: assign tex_offset %f %f",
index, psurf->tex_offset[0], psurf->tex_offset[1]
);
}
@ -533,7 +525,7 @@ static void patchFuncAnyEntity( const entity_props_t *props, uint32_t have_field
Q_strncpy(from_tex, from_begin, Q_min(sizeof from_tex, from_len + 1));
Q_strncpy(to_mat, to_begin, Q_min(sizeof to_mat, to_len + 1));
const int from_tex_index = XVK_FindTextureNamedLike(from_tex);
const int from_tex_index = R_TextureFindByNameLike(from_tex);
const r_vk_material_ref_t to_mat_ref = R_VkMaterialGetForName(to_mat);
DEBUG("Adding mapping from tex \"%s\"(%d) to mat \"%s\"(%d) for entity=%d",

View File

@ -23,7 +23,7 @@
X(11, string, target, String) \
X(12, int, style, Int) \
X(13, int_array_t, _xvk_surface_id, IntArray) \
X(14, string, _xvk_texture, String) \
X(14, string, _xvk_material, String) \
X(15, int_array_t, _xvk_ent_id, IntArray) \
X(16, float, _xvk_radius, Float) \
X(17, vec4_t, _xvk_svec, Vec4) \
@ -181,7 +181,7 @@ void XVK_ParseMapPatches( void );
enum {
Patch_Surface_NoPatch = 0,
Patch_Surface_Delete = (1<<0),
Patch_Surface_Texture = (1<<1),
Patch_Surface_Material = (1<<1),
Patch_Surface_Emissive = (1<<2),
Patch_Surface_STvecs = (1<<3),
Patch_Surface_TexOffset = (1<<4),
@ -193,11 +193,7 @@ struct texture_s;
typedef struct {
uint32_t flags;
// Static texture index in case there's no texture_s pointer
int tex_id;
// Pointer to texture_s data (which also may include animation)
const struct texture_s *tex;
r_vk_material_ref_t material_ref;
vec3_t emissive;

View File

@ -4,6 +4,7 @@
#include "vk_const.h"
#include "profiler.h"
#include "vk_logs.h"
#include "unordered_roadmap.h"
#include <stdio.h>
@ -12,12 +13,13 @@
#define MAX_INCLUDE_DEPTH 4
#define MAX_MATERIALS 2048
#define MAX_NEW_MATERIALS 128
static r_vk_material_t k_default_material = {
.tex_base_color = -1,
.tex_metalness = 0,
.tex_roughness = 0,
.tex_normalmap = 0,
.tex_normalmap = 0, // 0 means no normal map, checked in shaders
.metalness = 0.f,
.roughness = 1.f,
@ -60,6 +62,11 @@ typedef struct {
r_vk_material_t material;
} material_entry_t;
typedef struct {
urmom_header_t hdr_;
int mat_id; // into g_materials.table
} material_name_map_t;
static struct {
int count;
material_entry_t table[MAX_MATERIALS];
@ -69,7 +76,8 @@ static struct {
// TODO embed into tex_to_mat
r_vk_material_per_mode_t for_rendermode[kRenderTransAdd+1];
// TODO for name
urmom_desc_t map_desc;
material_name_map_t map[MAX_NEW_MATERIALS];
} g_materials;
static struct {
@ -83,7 +91,7 @@ static struct {
static int loadTexture( const char *filename, qboolean force_reload, colorspace_hint_e colorspace ) {
const uint64_t load_begin_ns = aprof_time_now_ns();
const int tex_id = R_VkLoadTexture( filename, colorspace, force_reload);
const int tex_id = R_TextureUploadFromFileExAcquire( filename, colorspace, force_reload );
DEBUG("Loaded texture %s => %d", filename, tex_id);
g_stats.texture_loads++;
g_stats.texture_load_duration_ns += aprof_time_now_ns() - load_begin_ns;
@ -115,6 +123,30 @@ static void printMaterial(int index) {
);
}
static void acquireTexturesForMaterial( int index ) {
const r_vk_material_t *mat = &g_materials.table[index].material;
DEBUG("%s(%d: %s)", __FUNCTION__, index, g_materials.table[index].name);
R_TextureAcquire(mat->tex_base_color);
R_TextureAcquire(mat->tex_metalness);
R_TextureAcquire(mat->tex_roughness);
if (mat->tex_normalmap > 0)
R_TextureAcquire(mat->tex_normalmap);
}
static void releaseTexturesForMaterialPtr( const r_vk_material_t *mat ) {
R_TextureRelease(mat->tex_base_color);
R_TextureRelease(mat->tex_metalness);
R_TextureRelease(mat->tex_roughness);
if (mat->tex_normalmap > 0)
R_TextureRelease(mat->tex_normalmap);
}
static void releaseTexturesForMaterial( int index ) {
const r_vk_material_t *mat = &g_materials.table[index].material;
DEBUG("%s(%d: %s)", __FUNCTION__, index, g_materials.table[index].name);
releaseTexturesForMaterialPtr( mat );
}
static int addMaterial(const char *name, const r_vk_material_t* mat) {
if (g_materials.count == MAX_MATERIALS) {
ERR("Max count of materials %d reached", MAX_MATERIALS);
@ -123,6 +155,7 @@ static int addMaterial(const char *name, const r_vk_material_t* mat) {
Q_strncpy(g_materials.table[g_materials.count].name, name, sizeof g_materials.table[g_materials.count].name);
g_materials.table[g_materials.count].material = *mat;
acquireTexturesForMaterial(g_materials.count);
printMaterial(g_materials.count);
@ -130,7 +163,7 @@ static int addMaterial(const char *name, const r_vk_material_t* mat) {
}
static void assignMaterialForTexture(const char *name, int for_tex_id, int mat_id) {
const char* const tex_name = findTexture(for_tex_id)->name;
const char* const tex_name = R_TextureGetNameByIndex(for_tex_id);
DEBUG("Assigning material \"%s\" for_tex_id=\"%s\"(%d)", name, tex_name, for_tex_id);
ASSERT(mat_id >= 0);
@ -155,7 +188,6 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
r_vk_material_t current_material = k_default_material;
int for_tex_id = -1;
int dummy_named_texture_fixme = -1;
qboolean force_reload = false;
qboolean create = false;
qboolean metalness_set = false;
@ -192,7 +224,6 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
if (key[0] == '{') {
current_material = k_default_material;
for_tex_id = -1;
dummy_named_texture_fixme = -1;
force_reload = false;
create = false;
metalness_set = false;
@ -203,38 +234,44 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
}
if (key[0] == '}') {
if (for_tex_id < 0 && !create) {
if (for_tex_id <= 0 && !create) {
// Skip this material, as its texture hasn't been loaded
// NOTE: might want to check whether it makes sense wrt late-loading stuff
continue;
}
if (!name[0]) {
if (name[0] == '\0') {
WARN("Unreferenceable (no \"for_texture\", no \"new\") material found in %s", filename);
continue;
}
#define LOAD_TEXTURE_FOR(name, field, colorspace) do { \
if (name[0] != '\0') { \
char texture_path[256]; \
MAKE_PATH(texture_path, name); \
const int tex_id = loadTexture(texture_path, force_reload, colorspace); \
if (tex_id < 0) { \
ERR("Failed to load texture \"%s\" for "#name"", name); \
// Start with *default texture for base color, it will be acquired if no replacement is specified or could be loaded.
current_material.tex_base_color = for_tex_id >= 0 ? for_tex_id : 0;
#define LOAD_TEXTURE_FOR(name, field, colorspace) \
do { \
if (name[0] != '\0') { \
char texture_path[256]; \
MAKE_PATH(texture_path, name); \
const int tex_id = loadTexture(texture_path, force_reload, colorspace); \
if (tex_id < 0) { \
ERR("Failed to load texture \"%s\" for "#name"", name); \
if (current_material.field > 0) \
R_TextureAcquire(current_material.field); \
} else { \
current_material.field = tex_id; \
} \
} else { \
current_material.field = tex_id; \
if (current_material.field > 0) \
R_TextureAcquire(current_material.field); \
} \
}} while(0)
} while(0)
LOAD_TEXTURE_FOR(basecolor_map, tex_base_color, kColorspaceNative);
LOAD_TEXTURE_FOR(normal_map, tex_normalmap, kColorspaceLinear);
LOAD_TEXTURE_FOR(metal_map, tex_metalness, kColorspaceLinear);
LOAD_TEXTURE_FOR(roughness_map, tex_roughness, kColorspaceLinear);
// If there's no explicit basecolor_map value, use the "for" target texture
if (current_material.tex_base_color == -1)
current_material.tex_base_color = for_tex_id >= 0 ? for_tex_id : 0;
if (!metalness_set && current_material.tex_metalness != tglob.whiteTexture) {
// If metalness factor wasn't set explicitly, but texture was specified, set it to match the texture value.
current_material.metalness = 1.f;
@ -242,21 +279,36 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
const int mat_id = addMaterial(name, &current_material);
releaseTexturesForMaterialPtr(&current_material);
if (mat_id < 0) {
ERR("Cannot add material \"%s\" for_tex_id=\"%s\"(%d)", name, for_tex_id >= 0 ? findTexture(for_tex_id)->name : "N/A", for_tex_id);
ERR("Cannot add material \"%s\" for_tex_id=\"%s\"(%d)", name, for_tex_id >= 0 ? R_TextureGetNameByIndex(for_tex_id) : "N/A", for_tex_id);
continue;
}
// FIXME have a personal hash map, don't use texture
if (dummy_named_texture_fixme > 0) {
assignMaterialForTexture(name, dummy_named_texture_fixme, mat_id);
if (create)
{
const urmom_insert_t insert = urmomInsert(&g_materials.map_desc, name);
if (insert.index < 0) {
ERR("Cannot add new material '%s', ran out of space (max=%d)", name, MAX_NEW_MATERIALS);
continue;
}
material_name_map_t *const item = g_materials.map + insert.index;
if (!insert.created)
WARN("Replacing material '%s'@%d %d=>%d", name, insert.index, item->mat_id, mat_id);
else
DEBUG("Mapping new material '%s'@%d => %d", name, insert.index, mat_id);
item->mat_id = mat_id;
}
// Assign from-texture mapping if there's a texture
if (for_tex_id >= 0) {
// Assign rendermode-specific materials
if (rendermode > 0) {
const char* const tex_name = findTexture(for_tex_id)->name;
const char* const tex_name = R_TextureGetNameByIndex(for_tex_id);
DEBUG("Adding material \"%s\" for_tex_id=\"%s\"(%d) for rendermode %d", name, tex_name, for_tex_id, rendermode);
r_vk_material_per_mode_t* const rm = g_materials.for_rendermode + rendermode;
@ -280,21 +332,23 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
if (!pos)
break;
//DEBUG("key=\"%s\", value=\"%s\"", key, value);
if (Q_stricmp(key, "for") == 0) {
if (name[0] != '\0')
WARN("Material already has \"new\" or \"for_texture\" old=\"%s\" new=\"%s\"", name, value);
const uint64_t lookup_begin_ns = aprof_time_now_ns();
for_tex_id = XVK_FindTextureNamedLike(value);
for_tex_id = R_TextureFindByNameLike(value);
DEBUG("R_TextureFindByNameLike(%s)=%d", value, for_tex_id);
if (for_tex_id >= 0)
ASSERT(Q_stristr(R_TextureGetNameByIndex(for_tex_id), value) != NULL);
g_stats.texture_lookup_duration_ns += aprof_time_now_ns() - lookup_begin_ns;
g_stats.texture_lookups++;
Q_strncpy(name, value, sizeof name);
} else if (Q_stricmp(key, "new") == 0) {
if (name[0] != '\0')
WARN("Material already has \"new\" or \"for_texture\" old=\"%s\" new=\"%s\"", name, value);
// TODO hash map here, don't depend on textures
dummy_named_texture_fixme = XVK_CreateDummyTexture(value);
Q_strncpy(name, value, sizeof name);
create = true;
} else if (Q_stricmp(key, "force_reload") == 0) {
@ -382,14 +436,29 @@ static int findFilenameExtension(const char *s, int len) {
return len;
}
static void materialsReleaseTextures( void ) {
for (int i = 1; i < g_materials.count; ++i)
releaseTexturesForMaterial(i);
}
void R_VkMaterialsReload( void ) {
const uint64_t begin_time_ns = aprof_time_now_ns();
memset(&g_stats, 0, sizeof(g_stats));
materialsReleaseTextures();
g_materials.count = 1;
memset(g_materials.tex_to_mat, 0, sizeof g_materials.tex_to_mat);
g_materials.map_desc = (urmom_desc_t){
.type = kUrmomStringInsensitive,
.array = g_materials.map,
.count = COUNTOF(g_materials.map),
.item_size = sizeof(g_materials.map[0]),
};
urmomInit(&g_materials.map_desc);
for (int i = 0; i < COUNTOF(g_materials.for_rendermode); ++i)
g_materials.for_rendermode[i].count = 0;
@ -481,7 +550,7 @@ r_vk_material_t R_VkMaterialGetForTextureWithFlags( int tex_index, uint32_t flag
// TODO check for replacement textures named in a predictable way
// If there are, create a new material and assign it here
const char* texname = findTexture(tex_index)->name;
const char* texname = R_TextureGetNameByIndex(tex_index);
DEBUG("Would try to load texture files by default names of \"%s\"", texname);
// If no PBR textures found, continue using legacy+default ones
@ -499,17 +568,24 @@ r_vk_material_t R_VkMaterialGetForTextureWithFlags( int tex_index, uint32_t flag
}
r_vk_material_ref_t R_VkMaterialGetForName( const char *name ) {
// FIXME proper hash table here, don't depend on textures
const int dummy_tex_id_fixme = VK_FindTexture(name);
if (dummy_tex_id_fixme == 0) {
ERR("Material with name \"%s\" not found", name);
// Find in internal map first
// New materials have preference over texture names
const int index = urmomFind(&g_materials.map_desc, name);
if (index >= 0)
return (r_vk_material_ref_t){.index = g_materials.map[index].mat_id};
DEBUG("Couldn't find material '%s', fallback to texture lookup", name);
// Find by texture name
const int tex_id = R_TextureFindByNameLike(name);
if (tex_id <= 0) {
ERR("Neither material nor texture with name \"%s\" was found", name);
return (r_vk_material_ref_t){.index = -1,};
}
ASSERT(dummy_tex_id_fixme >= 0);
ASSERT(dummy_tex_id_fixme < MAX_TEXTURES);
ASSERT(tex_id > 0);
ASSERT(tex_id < MAX_TEXTURES);
return (r_vk_material_ref_t){.index = g_materials.tex_to_mat[dummy_tex_id_fixme].mat_id};
return (r_vk_material_ref_t){.index = g_materials.tex_to_mat[tex_id].mat_id};
}
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref ) {
@ -547,3 +623,8 @@ qboolean R_VkMaterialGetEx( int tex_id, int rendermode, r_vk_material_t *out_mat
return false;
}
void R_VkMaterialsShutdown( void ) {
materialsReleaseTextures();
}

View File

@ -34,6 +34,8 @@ typedef struct { int index; } r_vk_material_ref_t;
// TODO: track "version" in high bits?
void R_VkMaterialsReload( void );
void R_VkMaterialsShutdown( void );
struct model_s;
void R_VkMaterialsLoadForModel( const struct model_s* mod );

View File

@ -91,7 +91,7 @@ void R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, f
if (!p) {
/* gEngine.Con_Printf(S_ERROR "VK FIXME %s(%f, %f, %f, %f, %f, %f, %f, %f, %d(%s))\n", __FUNCTION__, */
/* x, y, w, h, s1, t1, s2, t2, texnum, findTexture(texnum)->name); */
/* x, y, w, h, s1, t1, s2, t2, texnum, R_TextureGetByIndex(texnum)->name); */
return;
}
@ -120,7 +120,7 @@ static void drawFill( float x, float y, float w, float h, int r, int g, int b, i
const int prev_blending = vk_renderstate.blending_mode;
vk_renderstate.blending_mode = blending_mode;
vk_renderstate.tri_color = (color_rgba8_t){r, g, b, a};
R_DrawStretchPic(x, y, w, h, 0, 0, 1, 1, VK_FindTexture(REF_WHITE_TEXTURE));
R_DrawStretchPic(x, y, w, h, 0, 0, 1, 1, /* TODO what is this garbage, get it by number */ R_TextureFindByName(REF_WHITE_TEXTURE));
vk_renderstate.tri_color = prev_color;
vk_renderstate.blending_mode = prev_blending;
}
@ -145,7 +145,7 @@ static qboolean createPipelines( void )
/* }; */
VkDescriptorSetLayout descriptor_layouts[] = {
vk_desc.one_texture_layout,
vk_desc_fixme.one_texture_layout,
};
VkPipelineLayoutCreateInfo plci = {
@ -264,12 +264,12 @@ static void drawOverlay( VkCommandBuffer cmdbuf ) {
for (int i = 0; i < g2d.batch_count && g2d.batch[i].vertex_count > 0; ++i)
{
vk_texture_t *texture = findTexture(g2d.batch[i].texture);
const VkDescriptorSet tex_unorm = R_VkTextureGetDescriptorUnorm( g2d.batch[i].texture );
const VkPipeline pipeline = g2d.pipelines[g2d.batch[i].blending_mode];
if (texture->vk.descriptor_unorm)
if (tex_unorm)
{
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g2d.pipeline_layout, 0, 1, &texture->vk.descriptor_unorm, 0, NULL);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g2d.pipeline_layout, 0, 1, &tex_unorm, 0, NULL);
vkCmdDraw(cmdbuf, g2d.batch[i].vertex_count, 1, g2d.batch[i].vertex_offset, 0);
} // FIXME else what?
}
@ -291,7 +291,7 @@ void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, c
void R_DrawTileClear( int texnum, int x, int y, int w, int h )
{
PRINT_NOT_IMPLEMENTED_ARGS("%s", findTexture(texnum)->name );
PRINT_NOT_IMPLEMENTED_ARGS("%s", R_TextureGetNameByIndex(texnum));
}
void CL_FillRGBA( float x, float y, float w, float h, int r, int g, int b, int a )

View File

@ -1,7 +1,7 @@
#include "vk_ray_internal.h"
#include "vk_rtx.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_materials.h"
#include "vk_geometry.h"
#include "vk_render.h"

View File

@ -62,10 +62,10 @@ static qboolean createPipelines( void )
/* }; */
VkDescriptorSetLayout descriptor_layouts[] = {
vk_desc.one_uniform_buffer_layout,
vk_desc.one_texture_layout,
vk_desc.one_texture_layout,
vk_desc.one_uniform_buffer_layout,
vk_desc_fixme.one_uniform_buffer_layout,
vk_desc_fixme.one_texture_layout,
vk_desc_fixme.one_texture_layout,
vk_desc_fixme.one_uniform_buffer_layout,
};
VkPipelineLayoutCreateInfo plci = {
@ -321,7 +321,7 @@ qboolean VK_RenderInit( void ) {
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
.pBufferInfo = &dbi_uniform_data,
.dstSet = vk_desc.ubo_sets[0], // FIXME
.dstSet = vk_desc_fixme.ubo_sets[0], // FIXME
}, {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstBinding = 0,
@ -329,7 +329,7 @@ qboolean VK_RenderInit( void ) {
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC,
.pBufferInfo = &dbi_uniform_lights,
.dstSet = vk_desc.ubo_sets[1], // FIXME
.dstSet = vk_desc_fixme.ubo_sets[1], // FIXME
}};
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
}
@ -552,7 +552,7 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf, qboolean draw )
vkCmdBindIndexBuffer(cmdbuf, geom_buffer, 0, VK_INDEX_TYPE_UINT16);
}
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 3, 1, vk_desc.ubo_sets + 1, 1, &dlights_ubo_offset);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 3, 1, vk_desc_fixme.ubo_sets + 1, 1, &dlights_ubo_offset);
for (int i = 0; i < g_render_state.num_draw_commands; ++i) {
const draw_command_t *const draw = g_render_state.draw_commands + i;
@ -579,7 +579,7 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf, qboolean draw )
if (ubo_offset != draw->draw.ubo_offset)
{
ubo_offset = draw->draw.ubo_offset;
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 0, 1, vk_desc.ubo_sets, 1, &ubo_offset);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 0, 1, vk_desc_fixme.ubo_sets, 1, &ubo_offset);
}
if (pipeline != draw->draw.pipeline_index) {
@ -589,14 +589,16 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf, qboolean draw )
if (lightmap != draw->draw.lightmap) {
lightmap = draw->draw.lightmap;
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 2, 1, &findTexture(lightmap)->vk.descriptor_unorm, 0, NULL);
const VkDescriptorSet lm_unorm = R_VkTextureGetDescriptorUnorm(lightmap);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 2, 1, &lm_unorm, 0, NULL);
}
if (texture != draw->draw.texture)
{
texture = draw->draw.texture;
const VkDescriptorSet tex_unorm = R_VkTextureGetDescriptorUnorm(texture);
// TODO names/enums for binding points
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 1, 1, &findTexture(texture)->vk.descriptor_unorm, 0, NULL);
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 1, 1, &tex_unorm, 0, NULL);
}
// Only indexed mode is supported

View File

@ -1,7 +1,7 @@
#include "vk_core.h"
#include "vk_cvar.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_renderstate.h"
#include "vk_overlay.h"
#include "vk_scene.h"
@ -38,14 +38,13 @@ static qboolean R_SetDisplayTransform( ref_screen_rotation_t rotate, int x, int
return true;
}
// only called for GL contexts
static void GL_SetupAttributes( int safegl )
{
PRINT_NOT_IMPLEMENTED();
// Nothing to do for Vulkan
}
static void GL_ClearExtensions( void )
{
PRINT_NOT_IMPLEMENTED();
// Nothing to do for Vulkan
}
static void GL_BackendStartFrame_UNUSED( void )
{
@ -63,13 +62,13 @@ static void R_ShowTextures_UNUSED( void )
}
// texture management
static const byte *R_GetTextureOriginalBuffer( unsigned int idx )
static const byte *R_GetTextureOriginalBuffer_UNUSED( unsigned int idx )
{
PRINT_NOT_IMPLEMENTED();
return NULL;
}
static void GL_ProcessTexture( int texnum, float gamma, int topColor, int bottomColor )
static void GL_ProcessTexture_UNUSED( int texnum, float gamma, int topColor, int bottomColor )
{
PRINT_NOT_IMPLEMENTED();
}
@ -115,6 +114,30 @@ static void R_InitSkyClouds( struct mip_s *mt, struct texture_s *tx, qboolean cu
extern void GL_SubdivideSurface( msurface_t *fa );
static void Mod_UnloadTextures( model_t *mod )
{
ASSERT( mod != NULL );
switch( mod->type )
{
case mod_studio:
Mod_StudioUnloadTextures( mod->cache.data );
break;
case mod_alias:
// FIXME Mod_AliasUnloadTextures( mod->cache.data );
break;
case mod_brush:
VK_BrushUnloadTextures( mod );
break;
case mod_sprite:
Mod_SpriteUnloadTextures( mod->cache.data );
break;
default:
ASSERT( 0 );
break;
}
}
static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte *buffer )
{
qboolean loaded = true;
@ -152,6 +175,7 @@ static qboolean Mod_ProcessRenderData( model_t *mod, qboolean create, const byte
gEngine.drawFuncs->Mod_ProcessUserData( mod, create, buffer );
if( !create ) {
Mod_UnloadTextures( mod );
switch( mod->type ) {
case mod_brush:
// Empirically, this function only attempts to destroy the worldmodel before loading the next map.
@ -221,20 +245,26 @@ static const char *getParmName(int parm)
static int VK_RefGetParm( int parm, int arg )
{
vk_texture_t *tex = NULL;
// TODO all PARM_TEX handle in r_texture internally
switch(parm){
case PARM_TEX_WIDTH:
case PARM_TEX_SRC_WIDTH: // TODO why is this separate?
tex = findTexture(arg);
return tex->width;
case PARM_TEX_HEIGHT:
case PARM_TEX_SRC_WIDTH: // TODO why is this separate?
case PARM_TEX_SRC_HEIGHT:
tex = findTexture(arg);
return tex->height;
case PARM_TEX_FLAGS:
tex = findTexture(arg);
return tex->flags;
/* TODO
case PARM_TEX_SKYBOX:
case PARM_TEX_SKYTEXNUM:
case PARM_TEX_LIGHTMAP:
case PARM_TEX_TARGET:
case PARM_TEX_TEXNUM:
case PARM_TEX_DEPTH:
case PARM_TEX_GLFORMAT:
case PARM_TEX_ENCODE:
case PARM_TEX_MIPCOUNT:
case PARM_TEX_MEMORY:
*/
return R_TexturesGetParm( parm, arg );
case PARM_MODERNFLASHLIGHT:
if (CVAR_TO_BOOL( vk_rtx )) {
return true;
@ -452,6 +482,32 @@ static int VGUI_GenerateTexture( void )
return 0;
}
static const byte* R_TextureData_UNUSED( unsigned int texnum )
{
PRINT_NOT_IMPLEMENTED_ARGS("texnum=%d", texnum);
// We don't store original texture data
// TODO do we need to?
return NULL;
}
int R_CreateTexture_UNUSED( const char *name, int width, int height, const void *buffer, texFlags_t flags )
{
PRINT_NOT_IMPLEMENTED_ARGS("name=%s width=%d height=%d buffer=%p flags=%08x", name, width, height, buffer, flags);
return 0;
}
static int R_LoadTextureArray_UNUSED( const char **names, int flags )
{
PRINT_NOT_IMPLEMENTED();
return 0;
}
int R_CreateTextureArray_UNUSED( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags )
{
PRINT_NOT_IMPLEMENTED_ARGS("name=%s width=%d height=%d buffer=%p flags=%08x", name, width, height, buffer, flags);
return 0;
}
static const ref_device_t *pfnGetRenderDevice( unsigned int idx )
{
if( idx >= vk_core.num_devices )
@ -467,6 +523,7 @@ static const ref_interface_t gReffuncs =
R_GetConfigName,
R_SetDisplayTransform,
// only called for GL contexts
GL_SetupAttributes,
.GL_InitExtensions = NULL, // Unused in Vulkan renderer
GL_ClearExtensions,
@ -487,13 +544,16 @@ static const ref_interface_t gReffuncs =
CL_AddCustomBeam,
R_ProcessEntData,
// debug
.R_ShowTextures = R_ShowTextures_UNUSED,
R_GetTextureOriginalBuffer,
VK_LoadTextureFromBuffer,
GL_ProcessTexture,
XVK_SetupSky,
// texture management
.R_GetTextureOriginalBuffer = R_GetTextureOriginalBuffer_UNUSED,
.GL_LoadTextureFromBuffer = R_TextureUploadFromBuffer,
.GL_ProcessTexture = GL_ProcessTexture_UNUSED,
.R_SetupSky = R_TextureSetupSky,
// 2D
R_Set2DMode,
R_DrawStretchRaw,
R_DrawStretchPic,
@ -502,11 +562,14 @@ static const ref_interface_t gReffuncs =
CL_FillRGBABlend,
R_WorldToScreen,
// screenshot, cubemapshot
VID_ScreenShot,
VID_CubemapShot,
// light
R_LightPoint,
// decals
R_DecalShoot,
R_DecalRemoveAll,
R_CreateDecalList,
@ -540,15 +603,17 @@ static const ref_interface_t gReffuncs =
R_SetCurrentEntity,
R_SetCurrentModel,
VK_FindTexture,
VK_TextureName,
VK_TextureData,
VK_LoadTextureExternal,
VK_CreateTexture,
VK_LoadTextureArray,
VK_CreateTextureArray,
VK_FreeTexture,
// Texture tools
.GL_FindTexture = R_TextureFindByName,
.GL_TextureName = R_TextureGetNameByIndex,
.GL_TextureData = R_TextureData_UNUSED,
.GL_LoadTexture = R_TextureUploadFromFile,
.GL_CreateTexture = R_CreateTexture_UNUSED,
.GL_LoadTextureArray = R_LoadTextureArray_UNUSED,
.GL_CreateTextureArray = R_CreateTextureArray_UNUSED,
.GL_FreeTexture = R_TextureFree,
// Decals manipulating (draw & remove)
DrawSingleDecal,
R_DecalSetupVerts,
R_EntityRemoveDecals,

View File

@ -16,7 +16,7 @@ GNU General Public License for more details.
#include "vk_rpart.h"
#include "vk_triapi.h"
#include "camera.h"
#include "vk_textures.h" // tglob.particleTexture
#include "r_textures.h" // tglob.particleTexture
#include "vk_common.h"
#include "vk_sprite.h" // R_GetSpriteTexture

View File

@ -53,7 +53,8 @@
X(Buffer, lights) \
X(Buffer, light_grid) \
X(Texture, textures) \
X(Texture, skybox)
X(Texture, skybox) \
X(Texture, blue_noise_texture)
enum {
#define RES_ENUM(type, name) ExternalResource_##name,
@ -123,11 +124,15 @@ void VK_RayNewMap( void ) {
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
// FIXME we should pick tglob.dii_all_textures here directly
.value = (vk_descriptor_value_t){
.image = {
.sampler = tglob.default_sampler_fixme,
.imageView = tglob.skybox_cube.vk.image.view ? tglob.skybox_cube.vk.image.view : tglob.cubemap_placeholder.vk.image.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
},
.image = R_VkTexturesGetSkyboxDescriptorImageInfo(),
},
};
g_rtx.res[ExternalResource_blue_noise_texture].resource = (vk_resource_t){
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
// FIXME we should pick tglob.dii_all_textures here directly
.value = (vk_descriptor_value_t){
.image = R_VkTexturesGetBlueNoiseImageInfo(),
},
};
}
@ -429,6 +434,7 @@ static void reloadMainpipe(void) {
.debug_name = mr->name,
.width = FRAME_WIDTH,
.height = FRAME_HEIGHT,
.depth = 1,
.mips = 1,
.layers = 1,
.format = mr->image_format,
@ -614,7 +620,7 @@ qboolean VK_RayInit( void )
g_rtx.res[ExternalResource_textures].resource = (vk_resource_t){
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.value = (vk_descriptor_value_t){
.image_array = tglob.dii_all_textures,
.image_array = R_VkTexturesGetAllDescriptorsArray(),
}
};
g_rtx.res[ExternalResource_textures].refcount = 1;

View File

@ -13,7 +13,7 @@
#include "vk_beams.h"
#include "vk_light.h"
#include "vk_rtx.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_cvar.h"
#include "vk_materials.h"
#include "camera.h"
@ -257,8 +257,7 @@ void R_NewMap( void ) {
// Make sure that we're not rendering anything before starting to mess with GPU objects
XVK_CHECK(vkDeviceWaitIdle(vk_core.device));
XVK_SetupSky( gEngine.pfnGetMoveVars()->skyName );
R_TextureSetupSky( gEngine.pfnGetMoveVars()->skyName );
loadMap(map);

View File

@ -1,5 +1,5 @@
#include "vk_sprite.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "camera.h"
#include "vk_render.h"
#include "vk_geometry.h"
@ -242,12 +242,12 @@ static const dframetype_t *VK_SpriteLoadFrame( model_t *mod, const void *pin, ms
if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite
{
Q_snprintf( texname, sizeof( texname ), "#HUD/%s(%s:%i%i).spr", ctx->sprite_name, ctx->group_suffix, num / 10, num % 10 );
gl_texturenum = VK_LoadTextureExternal( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
gl_texturenum = R_TextureUploadFromFile( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
}
else
{
Q_snprintf( texname, sizeof( texname ), "#%s(%s:%i%i).spr", ctx->sprite_name, ctx->group_suffix, num / 10, num % 10 );
gl_texturenum = VK_LoadTextureExternal( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
gl_texturenum = R_TextureUploadFromFile( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
}
// setup frame description
@ -406,7 +406,6 @@ Loading a bitmap image as sprite with multiple frames
as pieces of input image
====================
*/
// IS NOT CALLED BY ANYTHING?!
void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean *loaded )
{
byte *src, *dst;
@ -509,7 +508,7 @@ void Mod_LoadMapSprite( model_t *mod, const void *buffer, size_t size, qboolean
pspriteframe->left = -( w >> 1 );
pspriteframe->down = ( h >> 1 ) - h;
pspriteframe->right = w + -( w >> 1 );
pspriteframe->gl_texturenum = VK_LoadTextureInternal( texname, &temp, TF_IMAGE );
pspriteframe->gl_texturenum = R_TextureUploadFromBuffer( texname, &temp, TF_IMAGE, false );
xl += w;
if( xl >= pix->width )
@ -1074,3 +1073,36 @@ void R_VkSpriteDrawModel( cl_entity_t *e, float blend )
}
*/
}
void Mod_SpriteUnloadTextures( void *data )
{
msprite_t *psprite;
mspritegroup_t *pspritegroup;
mspriteframe_t *pspriteframe;
int i, j;
psprite = data;
if( psprite )
{
// release all textures
for( i = 0; i < psprite->numframes; i++ )
{
if( psprite->frames[i].type == SPR_SINGLE )
{
pspriteframe = psprite->frames[i].frameptr;
R_TextureFree( pspriteframe->gl_texturenum );
}
else
{
pspritegroup = (mspritegroup_t *)psprite->frames[i].frameptr;
for( j = 0; j < pspritegroup->numframes; j++ )
{
pspriteframe = pspritegroup->frames[i];
R_TextureFree( pspriteframe->gl_texturenum );
}
}
}
}
}

View File

@ -14,3 +14,5 @@ void R_SpriteShutdown(void);
// FIXME needed to recreate the sprite quad model, otherwise its memory will be freed, reused and corrupted
void R_SpriteNewMapFIXME(void);
void Mod_SpriteUnloadTextures( void *data );

View File

@ -1,7 +1,7 @@
#include "vk_studio.h"
#include "com_model.h"
#include "vk_common.h"
#include "vk_textures.h"
#include "r_textures.h"
#include "vk_render.h"
#include "vk_geometry.h"
#include "vk_renderstate.h"
@ -2229,6 +2229,33 @@ static r_studio_submodel_info_t *studioModelFindSubmodelInfo(void) {
return NULL;
}
static material_mode_e studioMaterialModeForRenderType(vk_render_type_e render_type) {
switch (render_type) {
case kVkRenderTypeSolid:
return kMaterialMode_Opaque;
break;
case kVkRenderType_A_1mA_RW: // blend: scr*a + dst*(1-a), depth: RW
case kVkRenderType_A_1mA_R: // blend: scr*a + dst*(1-a), depth test
return kMaterialMode_Translucent;
break;
case kVkRenderType_A_1: // blend: scr*a + dst, no depth test or write; sprite:kRenderGlow only
return kMaterialMode_BlendGlow;
break;
case kVkRenderType_A_1_R: // blend: scr*a + dst, depth test
case kVkRenderType_1_1_R: // blend: scr + dst, depth test
return kMaterialMode_BlendAdd;
break;
case kVkRenderType_AT: // no blend, depth RW, alpha test
return kMaterialMode_AlphaTest;
break;
default:
gEngine.Host_Error("Unexpected render type %d\n", render_type);
}
return kMaterialMode_Opaque;
}
// Draws current studio model submodel
// Can be called externally, i.e. from game dll.
// Expects m_pStudioHeader, m_pSubModel, RI.currententity, etc to be already set up
@ -2300,7 +2327,7 @@ static void R_StudioDrawPoints( void ) {
// TODO r_model_draw_t.transform should be matrix3x4
const vk_render_type_e render_type = studioRenderModeToRenderType(RI.currententity->curstate.rendermode);
const material_mode_e material_mode = R_VkMaterialModeFromRenderType(render_type);
const material_mode_e material_mode = studioMaterialModeForRenderType(render_type);
R_RenderModelDraw(&render_submodel->model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
@ -3332,7 +3359,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
// build the texname
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );
ptexture->index = VK_LoadTextureExternal( texname, (byte *)ptexture, size, flags );
ptexture->index = R_TextureUploadFromFile( texname, (byte *)ptexture, size, flags );
if( !ptexture->index )
{
@ -3378,7 +3405,7 @@ void Mod_StudioUnloadTextures( void *data )
{
if( ptexture[i].index == tglob.defaultTexture )
continue;
VK_FreeTexture( ptexture[i].index );
R_TextureFree( ptexture[i].index );
}
}

View File

@ -10,6 +10,7 @@ void VK_StudioInit( void );
void VK_StudioShutdown( void );
void Mod_StudioLoadTextures( model_t *mod, void *data );
void Mod_StudioUnloadTextures( void *data );
void VK_StudioDrawModel( cl_entity_t *ent, int render_mode, float blend );

View File

@ -41,6 +41,7 @@ static void createDepthImage(int w, int h, VkFormat depth_format) {
.layers = 1,
.width = w,
.height = h,
.depth = 1,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
};

File diff suppressed because it is too large Load Diff

View File

@ -1,111 +1,46 @@
#pragma once
#include "r_textures.h"
#include "vk_core.h"
#include "vk_image.h"
#include "vk_const.h"
#include "xash3d_types.h"
#include "const.h"
#include "render_api.h"
#include "com_image.h"
#include "unordered_roadmap.h"
typedef struct vk_texture_s
{
char name[256];
int width, height;
texFlags_t flags;
uint texnum;
urmom_header_t hdr_;
int width, height, depth;
uint32_t flags;
int total_size;
struct {
r_vk_image_t image;
// TODO external table
VkDescriptorSet descriptor_unorm;
} vk;
uint hashValue;
struct vk_texture_s *nextHash;
int refcount;
qboolean ref_interface_visible;
int total_size;
// TODO "cache" eviction
// int used_maps_ago;
} vk_texture_t;
#define MAX_LIGHTMAPS 256
#define TEX_NAME(tex) ((tex)->hdr_.key)
#define MAX_SAMPLERS 8 // TF_NEAREST x 2 * TF_BORDER x 2 * TF_CLAMP x 2
qboolean R_VkTexturesInit( void );
void R_VkTexturesShutdown( void );
typedef struct vk_textures_global_s
{
poolhandle_t mempool;
int defaultTexture; // use for bad textures
int particleTexture;
int whiteTexture;
int grayTexture;
int blackTexture;
int solidskyTexture; // quake1 solid-sky layer
int alphaskyTexture; // quake1 alpha-sky layer
int lightmapTextures[MAX_LIGHTMAPS];
int dlightTexture; // custom dlight texture
int cinTexture; // cinematic texture
qboolean R_VkTexturesSkyboxUpload( const char *name, rgbdata_t *const sides[6], colorspace_hint_e colorspace_hint, qboolean placeholder);
// Hardcoded expected blue noise texture slot
// TODO consider moving it into a separate resource bindable by request
// TODO make it a 3D texture. Currently it's just a sequence of BLUE_NOISE_SIZE textures, loaded into consecutive slots.
#define BLUE_NOISE_TEXTURE_ID 7
qboolean R_VkTextureUpload(int index, vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, colorspace_hint_e colorspace_hint);
void R_VkTextureDestroy(int index, vk_texture_t *tex);
// Hardcode blue noise texture size to 64x64x64
#define BLUE_NOISE_SIZE 64
VkDescriptorImageInfo R_VkTexturesGetSkyboxDescriptorImageInfo( void );
const VkDescriptorImageInfo* R_VkTexturesGetAllDescriptorsArray( void );
VkDescriptorSet R_VkTextureGetDescriptorUnorm( uint index );
qboolean fCustomSkybox; // TODO do we need this for anything?
vk_texture_t skybox_cube;
vk_texture_t cubemap_placeholder;
// All textures descriptors in their native formats used for RT
VkDescriptorImageInfo dii_all_textures[MAX_TEXTURES];
// FIXME this should not exist, all textures should have their own samplers based on flags
VkSampler default_sampler_fixme;
struct {
texFlags_t flags;
VkSampler sampler;
} samplers[MAX_SAMPLERS];
} vk_textures_global_t;
// TODO rename this consistently
extern vk_textures_global_t tglob;
// Helper functions
void initTextures( void );
void destroyTextures( void );
vk_texture_t *findTexture(int index);
typedef enum {
kColorspaceNative,
kColorspaceLinear,
kColorspaceGamma,
} colorspace_hint_e;
// Public API functions
int VK_FindTexture( const char *name );
const char* VK_TextureName( unsigned int texnum );
const byte* VK_TextureData( unsigned int texnum );
int VK_LoadTextureExternal( const char *name, const byte *buf, size_t size, int flags );
int VK_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags );
int VK_LoadTextureArray( const char **names, int flags );
int VK_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
void VK_FreeTexture( unsigned int texnum );
int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
int R_VkLoadTexture( const char *filename, colorspace_hint_e colorspace, qboolean force_reload);
int XVK_TextureLookupF( const char *fmt, ...);
#define VK_LoadTextureInternal( name, pic, flags ) VK_LoadTextureFromBuffer( name, pic, flags, false )
void XVK_SetupSky( const char *skyboxname );
// Tries to find a texture by its short name
// Full names depend on map name, wad name, etc. This function tries them all.
// Returns -1 if not found
int XVK_FindTextureNamedLike( const char *texture_name );
int XVK_CreateDummyTexture( const char *name );
VkDescriptorImageInfo R_VkTexturesGetBlueNoiseImageInfo( void );

View File

@ -4,8 +4,6 @@
#include "vk_sprite.h" // R_GetSpriteTexture
#include "vk_logs.h"
#include "vk_textures.h" // FIXME temp
#include "xash3d_mathlib.h"
#define MAX_TRIAPI_VERTICES 1024

View File

@ -153,12 +153,28 @@ def build(bld):
#bld.install_files(bld.env.LIBDIR + '/valve', things)
bld.install_files(bld.env.LIBDIR,
bld.path.ant_glob('data/**'),
cwd=bld.path.find_dir('data/'),
relative_trick=True)
bld.path.ant_glob('data/**'),
cwd=bld.path.find_dir('data/'),
relative_trick=True)
#bld.program(features='test', defines=['ALOLCATOR_TEST'],source='alolcator.c', target='alolcator')
bld.add_post_fun(printTestSummary)
if bld.env.TESTS:
bld.program(
features='test',
defines=['ALOLCATOR_TEST'],
source='alolcator.c',
target='test_alolcator',
subsystem = bld.env.CONSOLE_SUBSYSTEM,
install_path = None)
#from waflib.Tools import waf_unit_test
#bld.add_post_fun(waf_unit_test.summary)
tests = {
'unordered_roadmap': 'tests/unordered_roadmap.c',
}
for i in tests:
bld.program(features = 'test',
source = tests[i],
target = 'test_%s' % i,
subsystem = bld.env.CONSOLE_SUBSYSTEM,
install_path = None)
#bld.add_post_fun(printTestSummary)