mirror of
https://github.com/w23/xash3d-fwgs
synced 2024-12-13 20:50:23 +01:00
vk: respect TF_NEAREST/CLAMP/BORDER flags (#471)
Use these flags to pick the right sampler. Fixes issues with blurry and leaking fonts, lines in main menu tiles, etc. fixes #439, fixes #79
This commit is contained in:
parent
6d7fd41494
commit
01de5957d8
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -802,7 +811,6 @@ void R_VkShutdown( void ) {
|
||||
|
||||
VK_DescriptorShutdown();
|
||||
|
||||
vkDestroySampler(vk_core.device, vk_core.default_sampler, NULL);
|
||||
R_VkStagingShutdown();
|
||||
|
||||
VK_DevMemDestroy();
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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 );
|
||||
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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 ));
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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 ))
|
||||
@ -872,28 +917,20 @@ 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,
|
||||
};
|
||||
return (tex - vk_textures);
|
||||
}
|
||||
|
||||
/* 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, ...) {
|
||||
|
@ -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
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user