add cubemap support; add misaligned skybox

This commit is contained in:
Ivan Avdeev 2021-11-21 14:53:51 -08:00
parent 714d825956
commit 1ad13817fe
7 changed files with 125 additions and 65 deletions

View File

@ -5,8 +5,9 @@
#include "ray_common.glsl"
#include "ray_kusochki.glsl"
layout (constant_id = 6) const uint MAX_TEXTURES = 4096;
layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
//layout (constant_id = 6) const uint MAX_TEXTURES = 4096;
//layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
layout (set = 0, binding = 13) uniform samplerCube skybox;
layout (set = 0, binding = 7/*, align=4*/) uniform UBOLights { Lights lights; };
layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload;
@ -19,9 +20,5 @@ void main() {
payload.base_color = vec3(1., 0., 1.);
payload.kusok_index = -1;
payload.material_index = 0;
payload.emissive = vec3(1., 0., 1.);
const uint tex_skyplane = lights.skybox_up;
const vec2 sky_uv = gl_WorldRayDirectionEXT.xy * .5 + .5;
payload.emissive = texture(textures[nonuniformEXT(tex_skyplane)], sky_uv).rgb;
payload.emissive = texture(skybox, gl_WorldRayDirectionEXT).rgb;
}

View File

@ -71,7 +71,7 @@ struct EmissiveKusok {
struct Lights {
uint num_kusochki;
uint num_point_lights;
uint skybox_rt, skybox_bk, skybox_lf, skybox_ft, skybox_up, skybox_dn;
PAD(2)
STRUCT EmissiveKusok kusochki[MAX_EMISSIVE_KUSOCHKI];
STRUCT PointLight point_lights[MAX_POINT_LIGHTS];
};

View File

@ -12,13 +12,14 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
.extent.height = create->height,
.extent.depth = 1,
.mipLevels = create->mips,
.arrayLayers = 1,
.arrayLayers = create->layers,
.format = create->format,
.tiling = create->tiling,
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.usage = create->usage,
.samples = VK_SAMPLE_COUNT_1_BIT,
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
.flags = create->is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0,
};
XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image));
@ -30,14 +31,14 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
image.devmem = allocateDeviceMemory(memreq, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
XVK_CHECK(vkBindImageMemory(vk_core.device, image.image, image.devmem.device_memory, 0));
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.viewType = create->is_cubemap ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D;
ivci.format = ici.format;
ivci.image = image.image;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = ici.mipLevels;
ivci.subresourceRange.baseArrayLayer = 0;
ivci.subresourceRange.layerCount = 1;
ivci.subresourceRange.layerCount = ici.arrayLayers;
ivci.components = (VkComponentMapping){0, 0, 0, create->has_alpha ? 0 : VK_COMPONENT_SWIZZLE_ONE};
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view));

View File

@ -15,11 +15,12 @@ typedef struct {
typedef struct {
const char *debug_name;
uint32_t width, height;
int mips, layers;
VkFormat format;
VkImageTiling tiling;
VkImageUsageFlags usage;
int mips;
qboolean has_alpha;
qboolean is_cubemap;
} xvk_image_create_t;
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create);

View File

@ -76,6 +76,8 @@ enum {
RayDescBinding_Dest_ImageAdditive = 11,
RayDescBinding_Dest_ImageNormals = 12,
RayDescBinding_SkyboxCube = 13,
RayDescBinding_COUNT
};
@ -613,6 +615,12 @@ static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render
g_rtx.desc_values[RayDescBinding_Textures].image_array = dii_all_textures;
g_rtx.desc_values[RayDescBinding_SkyboxCube].image = (VkDescriptorImageInfo){
.sampler = vk_core.default_sampler,
.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,
};
// TODO: move this to vk_texture.c
for (int i = 0; i < MAX_TEXTURES; ++i) {
const vk_texture_t *texture = findTexture(i);
@ -793,13 +801,6 @@ static void updateLights( void )
dst->environment = !!(src->flags & LightFlag_Environment);
}
lights->skybox_rt = tglob.skyboxTextures[0];
lights->skybox_bk = tglob.skyboxTextures[1];
lights->skybox_lf = tglob.skyboxTextures[2];
lights->skybox_ft = tglob.skyboxTextures[3];
lights->skybox_up = tglob.skyboxTextures[4];
lights->skybox_dn = tglob.skyboxTextures[5];
}
}
@ -1148,6 +1149,16 @@ static void createLayouts( void ) {
.pImmutableSamplers = NULL, //samplers,
};
g_rtx.desc_bindings[RayDescBinding_SkyboxCube] = (VkDescriptorSetLayoutBinding){
.binding = RayDescBinding_SkyboxCube,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR,
// FIXME on AMD using immutable samplers leads to nearest filtering ???!
.pImmutableSamplers = NULL, //samplers,
};
// for (int i = 0; i < ARRAYSIZE(samplers); ++i)
// samplers[i] = vk_core.default_sampler;
@ -1256,10 +1267,12 @@ qboolean VK_RayInit( void )
.width = FRAME_WIDTH, \
.height = FRAME_HEIGHT, \
.mips = 1, \
.layers = 1, \
.format = format_, \
.tiling = VK_IMAGE_TILING_OPTIMAL, \
.usage = VK_IMAGE_USAGE_STORAGE_BIT | add_usage_bits, \
.has_alpha = true, \
.is_cubemap = false, \
}; \
Q_snprintf(debug_name, sizeof(debug_name), "rtx frames[%d] " # name, i); \
g_rtx.frames[i].name = XVK_ImageCreate(&create); \

View File

@ -230,6 +230,8 @@ static void VK_ProcessImage( vk_texture_t *tex, rgbdata_t *pic )
}
}
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap);
static void VK_CreateInternalTextures( void )
{
int dx2, dy, d;
@ -290,6 +292,22 @@ static void VK_CreateInternalTextures( void )
// cinematic dummy
pic = Common_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR );
tglob.cinTexture = VK_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP );
{
rgbdata_t *sides[6];
pic = Common_FakeImage( 4, 4, 1, IMAGE_HAS_COLOR );
for( x = 0; x < 16; x++ )
((uint *)pic->buffer)[x] = 0xFFFFFFFF;
sides[0] = pic;
sides[1] = pic;
sides[2] = pic;
sides[3] = pic;
sides[4] = pic;
sides[5] = pic;
uploadTexture( &tglob.cubemap_placeholder, sides, 6, true );
}
}
static VkFormat VK_GetFormat(pixformat_t format)
@ -445,45 +463,67 @@ static void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, in
}
}
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) {
const VkFormat format = VK_GetFormat(pic->type);
const VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
const VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
byte *buf = pic->buffer;
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;
// TODO non-rbga textures
// TODO cubemaps
if (!pic->buffer)
return false;
for (int i = 0; i < num_layers; ++i) {
if (!layers[i]->buffer) {
gEngine.Con_Printf(S_ERROR "Texture %s layer %d missing buffer\n", tex->name, i);
return false;
}
tex->width = pic->width;
tex->height = pic->height;
mipCount = CalcMipmapCount( tex, ( buf != NULL ));
if (i == 0)
continue;
gEngine.Con_Reportf("Uploading texture %s, mips=%d\n", tex->name, mipCount);
if (layers[0]->type != layers[i]->type) {
gEngine.Con_Printf(S_ERROR "Texture %s layer %d has type %d inconsistent with layer 0 type %d\n", tex->name, i, layers[i]->type, layers[0]->type);
return false;
}
if (layers[0]->width != layers[i]->width || layers[0]->height != layers[i]->height) {
gEngine.Con_Printf(S_ERROR "Texture %s layer %d has resolution %dx%d inconsistent with layer 0 resolution %dx%d\n",
tex->name, i, layers[i]->width, layers[i]->height, layers[0]->width, layers[0]->height);
return false;
}
if ((layers[0]->flags ^ layers[i]->flags) & IMAGE_HAS_ALPHA) {
gEngine.Con_Printf(S_ERROR "Texture %s layer %d has_alpha=%d inconsistent with layer 0 has_alpha=%d\n",
tex->name, i,
!!(layers[i]->flags & IMAGE_HAS_ALPHA),
!!(layers[0]->flags & IMAGE_HAS_ALPHA));
}
}
tex->width = layers[0]->width;
tex->height = layers[0]->height;
mipCount = CalcMipmapCount( tex, true);
gEngine.Con_Reportf("Uploading texture %s, mips=%d, layers=%d\n", tex->name, mipCount, layers);
// TODO this vvv
// // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
// if(( tex->depth == 1 ) && (( pic->width != tex->width ) || ( pic->height != tex->height )))
// data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap );
// if(( tex->depth == 1 ) && (( layers->width != tex->width ) || ( layers->height != tex->height )))
// data = GL_ResampleTexture( buf, layers->width, layers->height, tex->width, tex->height, normalMap );
// else data = buf;
// if( !ImageDXT( pic->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( pic->flags, IMAGE_ONEBIT_ALPHA ))
// if( !ImageDXT( layers->type ) && !FBitSet( tex->flags, TF_NOMIPMAP ) && FBitSet( layers->flags, IMAGE_ONEBIT_ALPHA ))
// data = GL_ApplyFilter( data, tex->width, tex->height );
{
const xvk_image_create_t create = {
.debug_name = tex->name,
.width = pic->width,
.height = pic->height,
.width = tex->width,
.height = tex->height,
.mips = mipCount,
.layers = num_layers,
.format = format,
.tiling = tiling,
.usage = usage,
.has_alpha = pic->flags & IMAGE_HAS_ALPHA,
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.has_alpha = layers[0]->flags & IMAGE_HAS_ALPHA,
.is_cubemap = cubemap,
};
tex->vk.image = XVK_ImageCreate(&create);
}
@ -511,7 +551,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) {
.baseMipLevel = 0,
.levelCount = mipCount,
.baseArrayLayer = 0,
.layerCount = 1,
.layerCount = num_layers,
}};
XVK_CHECK(vkBeginCommandBuffer(vk_core.cb_tex, &beginfo));
@ -521,9 +561,10 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) {
0, 0, NULL, 0, NULL, 1, &image_barrier);
// 5.1.2 copyBufferToImage for all mip levels
{
for (int mip = 0; mip < mipCount; ++mip)
{
for (int layer = 0; layer < num_layers; ++layer) {
for (int mip = 0; mip < mipCount; ++mip) {
const rgbdata_t *const pic = layers[layer];
byte *buf = pic->buffer;
const int width = Q_max( 1, ( pic->width >> mip ));
const int height = Q_max( 1, ( pic->height >> mip ));
const size_t mip_size = CalcImageSize( pic->type, width, height, 1 );
@ -535,7 +576,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) {
region.imageSubresource = (VkImageSubresourceLayers){
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = mip,
.baseArrayLayer = 0,
.baseArrayLayer = layer,
.layerCount = 1,
};
region.imageExtent = (VkExtent3D){
@ -569,7 +610,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *pic) {
.baseMipLevel = 0,
.levelCount = mipCount,
.baseArrayLayer = 0,
.layerCount = 1,
.layerCount = num_layers,
};
vkCmdPipelineBarrier(vk_core.cb_tex,
VK_PIPELINE_STAGE_TRANSFER_BIT,
@ -676,7 +717,7 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
// upload texture
VK_ProcessImage( tex, pic );
if( !uploadTexture( tex, pic ))
if( !uploadTexture( tex, &pic, 1, false ))
{
memset( tex, 0, sizeof( vk_texture_t ));
gEngine.FS_FreeImage( pic ); // release source texture
@ -788,7 +829,7 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
VK_ProcessImage( tex, pic );
if( !uploadTexture( tex, pic ))
if( !uploadTexture( tex, &pic, 1, false ))
{
memset( tex, 0, sizeof( vk_texture_t ));
return 0;
@ -814,20 +855,12 @@ int XVK_TextureLookupF( const char *fmt, ...) {
return tex_id;
}
static void unloadSkybox( void )
{
int i;
// release old skybox
for( i = 0; i < 6; i++ )
{
if( !tglob.skyboxTextures[i] ) continue;
VK_FreeTexture( tglob.skyboxTextures[i] );
static void unloadSkybox( void ) {
if (tglob.skybox_cube.vk.image.image) {
XVK_ImageDestroy(&tglob.skybox_cube.vk.image);
memset(&tglob.skybox_cube, 0, sizeof(tglob.skybox_cube));
}
tglob.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes)
memset( tglob.skyboxTextures, 0, sizeof( tglob.skyboxTextures ));
tglob.fCustomSkybox = false;
}
@ -880,6 +913,7 @@ void XVK_SetupSky( const char *skyboxname )
char loadname[MAX_STRING];
char sidename[MAX_STRING];
int i, result, len;
rgbdata_t *sides[6];
if( !COM_CheckString( skyboxname ))
{
@ -915,18 +949,30 @@ void XVK_SetupSky( const char *skyboxname )
Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] );
else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] );
tglob.skyboxTextures[i] = VK_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY );
if( !tglob.skyboxTextures[i] ) break;
sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0);
if (!sides[i])
break;
gEngine.Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " );
}
if( i == 6 )
{
for (int j = 0; j < i; ++j)
gEngine.FS_FreeImage( sides[j] ); // release source texture
if( i != 6 )
goto fail;
if( !Common_CheckTexName( loadname ))
goto fail;
// needed? VK_ProcessImage( tex, pic );
if (uploadTexture(&tglob.skybox_cube, sides, 6, true)) {
tglob.fCustomSkybox = true;
gEngine.Con_DPrintf( "done\n" );
return; // loaded
}
fail:
gEngine.Con_DPrintf( "^2failed\n" );
unloadSkybox();
}

View File

@ -36,13 +36,15 @@ typedef struct vk_textures_global_s
int alphaskyTexture; // quake1 alpha-sky layer
int lightmapTextures[MAX_LIGHTMAPS];
int dlightTexture; // custom dlight texture
int skyboxTextures[6]; // skybox sides
int cinTexture; // cinematic texture
int skytexturenum; // this not a gl_texturenum!
int skyboxbasenum; // start with 5800 FIXME remove this, lewa says this is a GL1 hack
qboolean fCustomSkybox; // TODO do we need this for anything?
vk_texture_t skybox_cube;
vk_texture_t cubemap_placeholder;
} vk_textures_global_t;
// TODO rename this consistently