Skip to content

Commit

Permalink
vk: respect TF_NEAREST/CLAMP/BORDER flags
Browse files Browse the repository at this point in the history
Use these flags to pick the right samler. Fixes issues with blurry and
lieaking fonts, main menu tiles lines, etc

fixes #439, fixes #79
  • Loading branch information
w23 committed Mar 8, 2023
1 parent 6d7fd41 commit 101f61a
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 72 deletions.
50 changes: 29 additions & 21 deletions ref/vk/vk_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,35 @@ static qboolean initSurface( void )
return true;
}

// TODO modules
/*
typedef struct r_vk_module_s {
qboolean (*init)(void);
void (*destroy)(void);
// TODO next: dependecies, refcounts, ...
} r_vk_module_t;
#define LIST_MODULES(X) ...
=>
extern const r_vk_module_t vk_instance_module;
...
extern const r_vk_module_t vk_rtx_module;
...
=>
static const r_vk_module_t *const modules[] = {
&vk_instance_module,
&vk_device_module,
&vk_aftermath_module,
&vk_texture_module,
...
&vk_rtx_module,
...
};
*/

qboolean R_VkInit( void )
{
// FIXME !!!! handle initialization errors properly: destroy what has already been created
Expand Down Expand Up @@ -716,26 +745,6 @@ qboolean R_VkInit( void )
if (!R_VkStagingInit())
return false;

// TODO move this to vk_texture module
{
VkSamplerCreateInfo sci = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_LINEAR,
.minFilter = VK_FILTER_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT,// TODO CLAMP_TO_EDGE, for menus
.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT,//CLAMP_TO_EDGE,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT,
.anisotropyEnable = vk_core.physical_device.anisotropy_enabled,
.maxAnisotropy = vk_core.physical_device.properties.limits.maxSamplerAnisotropy,
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.minLod = 0.f,
.maxLod = 16.,
};
XVK_CHECK(vkCreateSampler(vk_core.device, &sci, NULL, &vk_core.default_sampler));
}

if (!VK_PipelineInit())
return false;

Expand Down Expand Up @@ -802,7 +811,6 @@ void R_VkShutdown( void ) {

VK_DescriptorShutdown();

vkDestroySampler(vk_core.device, vk_core.default_sampler, NULL);
R_VkStagingShutdown();

VK_DevMemDestroy();
Expand Down
2 changes: 0 additions & 2 deletions ref/vk/vk_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ typedef struct vulkan_core_s {
VkDevice device;
VkQueue queue;

VkSampler default_sampler;

unsigned int num_devices;
ref_device_t *devices;
} vulkan_core_t;
Expand Down
8 changes: 4 additions & 4 deletions ref/vk/vk_descriptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,20 +38,20 @@ qboolean VK_DescriptorInit( void )
{
const int num_sets = MAX_TEXTURES;
// ... TODO find better place for this; this should be per-pipeline/shader
VkDescriptorSetLayoutBinding bindings[] = { {
const VkDescriptorSetLayoutBinding bindings[] = { {
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = &vk_core.default_sampler,
.pImmutableSamplers = NULL,
}};
VkDescriptorSetLayoutCreateInfo dslci = {
const VkDescriptorSetLayoutCreateInfo dslci = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = ARRAYSIZE(bindings),
.pBindings = bindings,
};
VkDescriptorSetLayout* tmp_layouts = Mem_Malloc(vk_core.pool, sizeof(VkDescriptorSetLayout) * num_sets);
VkDescriptorSetAllocateInfo dsai = {
const VkDescriptorSetAllocateInfo dsai = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
.descriptorPool = vk_desc.pool,
.descriptorSetCount = num_sets,
Expand Down
3 changes: 2 additions & 1 deletion ref/vk/vk_rtx.c
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,10 @@ void VK_RayNewMap( void ) {

g_rtx.res[ExternalResource_skybox].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 = {
.sampler = vk_core.default_sampler,
.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,
},
Expand Down
125 changes: 81 additions & 44 deletions ref/vk/vk_textures.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,19 @@
static vk_texture_t vk_textures[MAX_TEXTURES];
static vk_texture_t* vk_texturesHashTable[TEXTURES_HASH_SIZE];
static uint vk_numTextures;
vk_textures_global_t tglob;
vk_textures_global_t tglob = {0};

static void VK_CreateInternalTextures(void);
static VkSampler pickSamplerForFlags( texFlags_t flags );

void initTextures( void )
{
void initTextures( void ) {
memset( vk_textures, 0, sizeof( vk_textures ));
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
vk_numTextures = 0;

tglob.default_sampler_fixme = pickSamplerForFlags(0);
ASSERT(tglob.default_sampler_fixme != VK_NULL_HANDLE);

// create unused 0-entry
Q_strncpy( vk_textures->name, "*unused*", sizeof( vk_textures->name ));
vk_textures->hashValue = COM_HashKey( vk_textures->name, TEXTURES_HASH_SIZE );
Expand All @@ -49,14 +52,19 @@ void initTextures( void )
gEngine.Cmd_AddCommand( "texturelist", R_TextureList_f, "display loaded textures list" );
*/

// Fill empty texture with references to the default texture
{
const vk_texture_t *const default_texture = vk_textures + tglob.defaultTexture;
const VkImageView default_view = vk_textures[tglob.defaultTexture].vk.image.view;
ASSERT(default_view != VK_NULL_HANDLE);
for (int i = 0; i < MAX_TEXTURES; ++i) {
const vk_texture_t *const tex = findTexture(i);;
const vk_texture_t *const tex = vk_textures + i;
if (tex->vk.image.view)
continue;

tglob.dii_all_textures[i] = (VkDescriptorImageInfo){
.imageView = tex->vk.image.view != VK_NULL_HANDLE ? tex->vk.image.view : default_texture->vk.image.view,
.imageView = default_view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.sampler = vk_core.default_sampler,
.sampler = tglob.default_sampler_fixme,
};
}
}
Expand All @@ -74,6 +82,11 @@ void destroyTextures( void )
XVK_ImageDestroy(&tglob.cubemap_placeholder.vk.image);
memset(&tglob.cubemap_placeholder, 0, sizeof(tglob.cubemap_placeholder));

for (int i = 0; i < ARRAYSIZE(tglob.samplers); ++i) {
if (tglob.samplers[i].sampler != VK_NULL_HANDLE)
vkDestroySampler(vk_core.device, tglob.samplers[i].sampler, NULL);
}

//memset( tglob.lightmapTextures, 0, sizeof( tglob.lightmapTextures ));
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
memset( vk_textures, 0, sizeof( vk_textures ));
Expand Down Expand Up @@ -479,6 +492,48 @@ static void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, in
}
}

static VkSampler createSamplerForFlags( texFlags_t flags ) {
VkSampler sampler;
const VkFilter filter_mode = (flags & TF_NEAREST) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;
const VkSamplerAddressMode addr_mode =
(flags & TF_BORDER) ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
: ((flags & TF_CLAMP) ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT);
const VkSamplerCreateInfo sci = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = filter_mode,
.minFilter = filter_mode,
.addressModeU = addr_mode,
.addressModeV = addr_mode,
.addressModeW = addr_mode,
.anisotropyEnable = vk_core.physical_device.anisotropy_enabled,
.maxAnisotropy = vk_core.physical_device.properties.limits.maxSamplerAnisotropy,
.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK,
.unnormalizedCoordinates = VK_FALSE,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.minLod = 0.f,
.maxLod = 16.,
};
XVK_CHECK(vkCreateSampler(vk_core.device, &sci, NULL, &sampler));
return sampler;
}

static VkSampler pickSamplerForFlags( texFlags_t flags ) {
flags &= (TF_BORDER | TF_CLAMP | TF_NEAREST);

for (int i = 0; i < ARRAYSIZE(tglob.samplers); ++i) {
if (tglob.samplers[i].sampler == VK_NULL_HANDLE) {
tglob.samplers[i].flags = flags;
return tglob.samplers[i].sampler = createSamplerForFlags(flags);
}

if (tglob.samplers[i].flags == flags)
return tglob.samplers[i].sampler;
}

gEngine.Con_Printf(S_ERROR "Couldn't find/allocate sampler for flags %x\n", flags);
return tglob.default_sampler_fixme;
}

static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap) {
const VkFormat format = VK_GetFormat(layers[0]->type);
int mipCount = 0;
Expand Down Expand Up @@ -642,21 +697,25 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
// TODO how should we approach this:
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
// - update descriptor sets in batch?
if (vk_desc.next_free != MAX_TEXTURES)
{
VkDescriptorImageInfo dii_tex = {
if (vk_desc.next_free != MAX_TEXTURES) {
const int index = tex - vk_textures;
VkDescriptorImageInfo dii_tmp;
// FIXME handle cubemaps properly w/o this garbage. they should be the same as regular textures.
VkDescriptorImageInfo *const dii_tex = (num_layers == 1) ? tglob.dii_all_textures + index : &dii_tmp;
*dii_tex = (VkDescriptorImageInfo){
.imageView = tex->vk.image.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.sampler = pickSamplerForFlags( tex->flags ),
};
VkWriteDescriptorSet wds[] = { {
const VkWriteDescriptorSet wds[] = { {
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &dii_tex,
.pImageInfo = dii_tex,
.dstSet = tex->vk.descriptor = vk_desc.sets[vk_desc.next_free++],
}};
wds[0].dstSet = tex->vk.descriptor = vk_desc.sets[vk_desc.next_free++];
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
}
else
Expand Down Expand Up @@ -735,19 +794,6 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
return 0;
}

{
const int index = tex - vk_textures;
tglob.dii_all_textures[index] = (VkDescriptorImageInfo){
.imageView = tex->vk.image.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.sampler = vk_core.default_sampler,
};
}

/* FIXME
VK_ApplyTextureParams( tex ); // update texture filter, wrap etc
*/

tex->width = pic->width;
tex->height = pic->height;

Expand Down Expand Up @@ -842,12 +888,11 @@ void VK_FreeTexture( unsigned int texnum ) {
tglob.dii_all_textures[texnum] = (VkDescriptorImageInfo){
.imageView = vk_textures[tglob.defaultTexture].vk.image.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.sampler = vk_core.default_sampler,
.sampler = tglob.default_sampler_fixme,
};
}

int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update )
{
static int loadTextureFromBuffers( const char *name, rgbdata_t *const *const pic, int pic_count, texFlags_t flags, qboolean update ) {
vk_texture_t *tex;

if( !Common_CheckTexName( name ))
Expand All @@ -872,30 +917,22 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
tex = Common_AllocTexture( name, flags );
}

VK_ProcessImage( tex, pic );
for (int i = 0; i < pic_count; ++i)
VK_ProcessImage( tex, pic[i] );

if( !uploadTexture( tex, &pic, 1, false ))
if( !uploadTexture( tex, pic, pic_count, false ))
{
memset( tex, 0, sizeof( vk_texture_t ));
return 0;
}

{
const int index = tex - vk_textures;
tglob.dii_all_textures[index] = (VkDescriptorImageInfo){
.imageView = tex->vk.image.view,
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
.sampler = vk_core.default_sampler,
};
}

/* FIXME
VK_ApplyTextureParams( tex ); // update texture filter, wrap etc
*/

return (tex - vk_textures);
}

int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update ) {
return loadTextureFromBuffers(name, &pic, 1, flags, update);
}

int XVK_TextureLookupF( const char *fmt, ...) {
int tex_id = 0;
char buffer[1024];
Expand Down
10 changes: 10 additions & 0 deletions ref/vk/vk_textures.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ typedef struct vk_texture_s

#define MAX_LIGHTMAPS 256

#define MAX_SAMPLERS 8 // TF_NEAREST x 2 * TF_BORDER x 2 * TF_CLAMP x 2

typedef struct vk_textures_global_s
{
int defaultTexture; // use for bad textures
Expand All @@ -48,6 +50,14 @@ typedef struct vk_textures_global_s
vk_texture_t cubemap_placeholder;

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
Expand Down

0 comments on commit 101f61a

Please sign in to comment.