Merge pull request #222 from w23/E170
Streams 170-172. - implements skybox, fixes #140 - improves material reloading, fixes #207
This commit is contained in:
commit
ecaac9d4c7
|
@ -7,6 +7,7 @@
|
|||
|
||||
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(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload;
|
||||
|
||||
|
@ -79,6 +80,30 @@ void main() {
|
|||
const uint vi2 = uint(indices[first_index_offset+1]) + kusochki[kusok_index].vertex_offset;
|
||||
const uint vi3 = uint(indices[first_index_offset+2]) + kusochki[kusok_index].vertex_offset;
|
||||
|
||||
const vec3 pos[3] = {
|
||||
gl_ObjectToWorldEXT * vec4(vertices[vi1].pos, 1.),
|
||||
gl_ObjectToWorldEXT * vec4(vertices[vi2].pos, 1.),
|
||||
gl_ObjectToWorldEXT * vec4(vertices[vi3].pos, 1.),
|
||||
};
|
||||
// This one is supposed to be numerically better, but I can't see why
|
||||
const vec3 hit_pos = pos[0] * (1. - bary.x - bary.y) + pos[1] * bary.x + pos[2] * bary.y;
|
||||
//const vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT
|
||||
|
||||
const uint tex_base_color = kusochki[kusok_index].tex_base_color;
|
||||
if ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) {
|
||||
payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT);
|
||||
payload.base_color = vec3(0.);
|
||||
payload.transmissiveness = 0.;
|
||||
payload.normal = vec3(0.);
|
||||
payload.geometry_normal = vec3(0.);
|
||||
payload.emissive = pow(texture(skybox, gl_WorldRayDirectionEXT).rgb, vec3(2.2)); // Why?! See #230
|
||||
payload.kusok_index = -1;
|
||||
payload.roughness = 0.;
|
||||
payload.metalness = 0.;
|
||||
payload.material_index = tex_base_color;
|
||||
return;
|
||||
}
|
||||
|
||||
const vec3 n1 = vertices[vi1].normal;
|
||||
const vec3 n2 = vertices[vi2].normal;
|
||||
const vec3 n3 = vertices[vi3].normal;
|
||||
|
@ -94,11 +119,6 @@ void main() {
|
|||
vertices[vi3].gl_tc,
|
||||
};
|
||||
|
||||
const vec3 pos[3] = {
|
||||
gl_ObjectToWorldEXT * vec4(vertices[vi1].pos, 1.),
|
||||
gl_ObjectToWorldEXT * vec4(vertices[vi2].pos, 1.),
|
||||
gl_ObjectToWorldEXT * vec4(vertices[vi3].pos, 1.),
|
||||
};
|
||||
const vec2 texture_uv_stationary = vertices[vi1].gl_tc * (1. - bary.x - bary.y) + vertices[vi2].gl_tc * bary.x + vertices[vi3].gl_tc * bary.y;
|
||||
const vec2 texture_uv = texture_uv_stationary + push_constants.time * kusochki[kusok_index].uv_speed;
|
||||
|
||||
|
@ -106,15 +126,11 @@ void main() {
|
|||
const float geom_normal_sign = sign(dot(real_geom_normal, -gl_WorldRayDirectionEXT));
|
||||
const vec3 geom_normal = geom_normal_sign * real_geom_normal;
|
||||
|
||||
// This one is supposed to be numerically better, but I can't see why
|
||||
const vec3 hit_pos = pos[0] * (1. - bary.x - bary.y) + pos[1] * bary.x + pos[2] * bary.y + geom_normal * normal_offset_fudge;
|
||||
//const vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT + geom_normal * normal_offset_fudge;
|
||||
|
||||
const float ray_cone_width = payload.pixel_cone_spread_angle * payload.t_offset;
|
||||
vec4 uv_lods;
|
||||
computeAnisotropicEllipseAxes(hit_pos, /* TODO geom_?*/ normal, gl_WorldRayDirectionEXT, ray_cone_width, pos, uvs, texture_uv_stationary, uv_lods.xy, uv_lods.zw);
|
||||
|
||||
const uint tex_index = kusochki[kusok_index].tex_base_color;
|
||||
const uint tex_index = tex_base_color;
|
||||
const vec4 tex_color = sampleTexture(tex_index, texture_uv, uv_lods);
|
||||
//const vec3 base_color = pow(tex_color.rgb, vec3(2.));
|
||||
const vec3 base_color = ((push_constants.flags & PUSH_FLAG_LIGHTMAP_ONLY) != 0) ? vec3(1.) : tex_color.rgb;// pow(tex_color.rgb, vec3(2.));
|
||||
|
@ -135,7 +151,7 @@ void main() {
|
|||
|
||||
// FIXME read alpha from texture
|
||||
|
||||
payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT);
|
||||
payload.hit_pos_t = vec4(hit_pos + geom_normal * normal_offset_fudge, gl_HitTEXT);
|
||||
payload.base_color = base_color * kusochki[kusok_index].color.rgb;
|
||||
payload.transmissiveness = (1. - tex_color.a * kusochki[kusok_index].color.a);
|
||||
payload.normal = normal;
|
||||
|
|
|
@ -16,6 +16,7 @@ const float throughput_threshold = 1e-3;
|
|||
|
||||
layout (constant_id = 4) const float LIGHT_GRID_CELL_SIZE = 256.;
|
||||
layout (constant_id = 5) const uint MAX_LIGHT_CLUSTERS = 32768;
|
||||
layout (constant_id = 7) const uint SBT_RECORD_SIZE = 64;
|
||||
|
||||
//const uint LIGHT_CLUSTER_SIZE = 2 + MAX_VISIBLE_POINT_LIGHTS + MAX_VISIBLE_SURFACE_LIGHTS;
|
||||
//const uint LIGHT_CLUSTER_NUM_DLIGHTS_OFFSET = 0;
|
||||
|
@ -51,7 +52,7 @@ layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadEXT RayPayloadShadow payloa
|
|||
layout(location = PAYLOAD_LOCATION_ADDITIVE) rayPayloadEXT RayPayloadAdditive payload_additive;
|
||||
|
||||
bool shadowed(vec3 pos, vec3 dir, float dist) {
|
||||
payload_shadow.shadow = true;
|
||||
payload_shadow.hit_type = SHADOW_HIT;
|
||||
const uint flags = 0
|
||||
//| gl_RayFlagsCullFrontFacingTrianglesEXT
|
||||
//| gl_RayFlagsOpaqueEXT
|
||||
|
@ -63,7 +64,24 @@ bool shadowed(vec3 pos, vec3 dir, float dist) {
|
|||
GEOMETRY_BIT_OPAQUE,
|
||||
0, 0, SHADER_OFFSET_MISS_SHADOW,
|
||||
pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW);
|
||||
return payload_shadow.shadow;
|
||||
return payload_shadow.hit_type == SHADOW_HIT;
|
||||
}
|
||||
|
||||
// TODO join with just shadowed()
|
||||
bool shadowedSky(vec3 pos, vec3 dir, float dist) {
|
||||
payload_shadow.hit_type = SHADOW_HIT;
|
||||
const uint flags = 0
|
||||
//| gl_RayFlagsCullFrontFacingTrianglesEXT
|
||||
//| gl_RayFlagsOpaqueEXT
|
||||
//| gl_RayFlagsTerminateOnFirstHitEXT
|
||||
//| gl_RayFlagsSkipClosestHitShaderEXT
|
||||
;
|
||||
traceRayEXT(tlas,
|
||||
flags,
|
||||
GEOMETRY_BIT_OPAQUE,
|
||||
SHADER_OFFSET_HIT_SHADOW, SBT_RECORD_SIZE, SHADER_OFFSET_MISS_SHADOW,
|
||||
pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_SHADOW);
|
||||
return payload_shadow.hit_type != SHADOW_SKY;
|
||||
}
|
||||
|
||||
// This is an entry point for evaluation of all other BRDFs based on selected configuration (for direct light)
|
||||
|
@ -182,9 +200,9 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
|
|||
const float stopdot = lights.point_lights[i].color_stopdot.a;
|
||||
const vec3 dir = lights.point_lights[i].dir_stopdot2.xyz;
|
||||
const float stopdot2 = lights.point_lights[i].dir_stopdot2.a;
|
||||
const bool environment = (lights.point_lights[i].environment == 0);
|
||||
const bool not_environment = (lights.point_lights[i].environment == 0);
|
||||
|
||||
const vec3 light_dir = environment ? (origin_r.xyz - payload_opaque.hit_pos_t.xyz) : -dir; // TODO need to randomize sampling direction for environment soft shadow
|
||||
const vec3 light_dir = not_environment ? (origin_r.xyz - payload_opaque.hit_pos_t.xyz) : -dir; // TODO need to randomize sampling direction for environment soft shadow
|
||||
const vec3 light_dir_norm = normalize(light_dir);
|
||||
const float light_dot = dot(light_dir_norm, payload_opaque.normal);
|
||||
if (light_dot < 1e-5)
|
||||
|
@ -199,8 +217,8 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
|
|||
spot_attenuation = (spot_dot - stopdot2) / (stopdot - stopdot2);
|
||||
|
||||
float fdist = 1.f;
|
||||
float light_dist = 1e6; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too?
|
||||
if (environment) {
|
||||
float light_dist = 1e4; // TODO this is supposedly not the right way to do shadows for environment lights. qrad checks for hitting SURF_SKY, and maybe we should too?
|
||||
if (not_environment) {
|
||||
#if 1
|
||||
const float d2 = dot(light_dir, light_dir);
|
||||
const float r2 = origin_r.w * origin_r.w;
|
||||
|
@ -221,7 +239,6 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
|
|||
// if (dot(color,color) < color_culling_threshold)
|
||||
// continue;
|
||||
|
||||
// TODO split into diffuse and specular for denoiser
|
||||
vec3 ldiffuse, lspecular;
|
||||
evalSplitBRDF(payload_opaque.normal, light_dir_norm, view_dir, material, ldiffuse, lspecular);
|
||||
ldiffuse *= color;
|
||||
|
@ -232,9 +249,14 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
|
|||
if (dot(combined,combined) < color_culling_threshold)
|
||||
continue;
|
||||
|
||||
// TODO for environment light check that we've hit SURF_SKY
|
||||
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
||||
continue;
|
||||
if (not_environment) {
|
||||
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
||||
continue;
|
||||
} else {
|
||||
// for environment light check that we've hit SURF_SKY
|
||||
if (shadowedSky(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
||||
continue;
|
||||
}
|
||||
|
||||
diffuse += ldiffuse;
|
||||
specular += lspecular;
|
||||
|
@ -365,7 +387,7 @@ void main() {
|
|||
vec3 additive = traceAdditive(origin, direction, payload_opaque.hit_pos_t.w <= 0. ? L : payload_opaque.hit_pos_t.w);
|
||||
|
||||
// Sky/envmap
|
||||
if (payload_opaque.hit_pos_t.w <= 0.) {
|
||||
if (payload_opaque.kusok_index < 0) {
|
||||
if (bounce == 0) {
|
||||
out_additive += payload_opaque.emissive * color_factor + additive;
|
||||
} else {
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
#version 460 core
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
#extension GL_GOOGLE_include_directive : require
|
||||
|
||||
#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 (set = 0, binding = 7/*, align=4*/) uniform UBOLights { Lights lights; };
|
||||
|
||||
layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload;
|
||||
|
||||
void main() {
|
||||
|
@ -20,8 +15,4 @@ void main() {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,13 @@ struct RayPayloadOpaque {
|
|||
vec4 debug;
|
||||
};
|
||||
|
||||
|
||||
#define SHADOW_MISS 0
|
||||
#define SHADOW_HIT 1
|
||||
#define SHADOW_SKY 2
|
||||
|
||||
struct RayPayloadShadow {
|
||||
bool shadow;
|
||||
uint hit_type;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -32,6 +32,9 @@ layout (constant_id = 3) const uint MAX_VISIBLE_SURFACE_LIGHTS = 255;
|
|||
#define SHADER_OFFSET_HIT_REGULAR 0
|
||||
#define SHADER_OFFSET_HIT_ALPHA_TEST 1
|
||||
#define SHADER_OFFSET_HIT_ADDITIVE 2
|
||||
#define SHADER_OFFSET_HIT_SHADOW 3
|
||||
|
||||
#define KUSOK_MATERIAL_FLAG_SKYBOX 0x80000000
|
||||
|
||||
struct Kusok {
|
||||
uint index_offset;
|
||||
|
@ -71,7 +74,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];
|
||||
};
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
#version 460 core
|
||||
#extension GL_EXT_ray_tracing: require
|
||||
|
||||
#include "ray_kusochki.glsl"
|
||||
#include "ray_common.glsl"
|
||||
|
||||
layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow;
|
||||
|
||||
void main() {
|
||||
const int instance_kusochki_offset = gl_InstanceCustomIndexEXT;
|
||||
const int kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT;
|
||||
const uint tex_base_color = kusochki[kusok_index].tex_base_color;
|
||||
|
||||
payload_shadow.hit_type = ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) ? SHADOW_HIT : SHADOW_SKY ;
|
||||
}
|
|
@ -6,5 +6,5 @@
|
|||
layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow;
|
||||
|
||||
void main() {
|
||||
payload_shadow.shadow = false;
|
||||
payload_shadow.hit_type = SHADOW_MISS;
|
||||
}
|
||||
|
|
|
@ -382,8 +382,9 @@ static qboolean renderableSurface( const msurface_t *surf, int i ) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Explicitly enable SURF_SKY, otherwise they will be skipped by SURF_DRAWTILED
|
||||
if( FBitSet( surf->flags, SURF_DRAWSKY )) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if( FBitSet( surf->flags, SURF_DRAWTILED )) {
|
||||
|
@ -409,7 +410,6 @@ static model_sizes_t computeSizes( const model_t *mod ) {
|
|||
const msurface_t *surf = mod->surfaces + mod->firstmodelsurface + i;
|
||||
|
||||
sizes.water_surfaces += !!(surf->flags & (SURF_DRAWTURB | SURF_DRAWTURB_QUADS));
|
||||
//sizes.sky_surfaces += !!(surf->flags & SURF_DRAWSKY);
|
||||
|
||||
if (!renderableSurface(surf, i))
|
||||
continue;
|
||||
|
@ -487,7 +487,9 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
|||
model_geometry->material = kXVkMaterialSky;
|
||||
} else {
|
||||
model_geometry->material = kXVkMaterialRegular;
|
||||
VK_CreateSurfaceLightmap( surf, mod );
|
||||
if (!FBitSet( surf->flags, SURF_DRAWTILED )) {
|
||||
VK_CreateSurfaceLightmap( surf, mod );
|
||||
}
|
||||
}
|
||||
|
||||
if (FBitSet( surf->flags, SURF_CONVEYOR )) {
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
#include "vk_image.h"
|
||||
|
||||
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
||||
xvk_image_t image;
|
||||
VkMemoryRequirements memreq;
|
||||
VkImageViewCreateInfo ivci = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||
|
||||
VkImageCreateInfo ici = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.extent.width = create->width,
|
||||
.extent.height = create->height,
|
||||
.extent.depth = 1,
|
||||
.mipLevels = create->mips,
|
||||
.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));
|
||||
|
||||
if (create->debug_name)
|
||||
SET_DEBUG_NAME(image.image, VK_OBJECT_TYPE_IMAGE, create->debug_name);
|
||||
|
||||
vkGetImageMemoryRequirements(vk_core.device, image.image, &memreq);
|
||||
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 = 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 = 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));
|
||||
|
||||
if (create->debug_name)
|
||||
SET_DEBUG_NAME(image.view, VK_OBJECT_TYPE_IMAGE_VIEW, create->debug_name);
|
||||
|
||||
image.width = create->width;
|
||||
image.height = create->height;
|
||||
image.mips = create->mips;
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void XVK_ImageDestroy(xvk_image_t *img) {
|
||||
vkDestroyImageView(vk_core.device, img->view, NULL);
|
||||
vkDestroyImage(vk_core.device, img->image, NULL);
|
||||
freeDeviceMemory(&img->devmem);
|
||||
*img = (xvk_image_t){0};
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include "vk_core.h"
|
||||
|
||||
typedef struct {
|
||||
// FIXME better memory allocation
|
||||
// OCHEN PLOHO
|
||||
device_memory_t devmem;
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
|
||||
uint32_t width, height;
|
||||
int mips;
|
||||
} xvk_image_t;
|
||||
|
||||
typedef struct {
|
||||
const char *debug_name;
|
||||
uint32_t width, height;
|
||||
int mips, layers;
|
||||
VkFormat format;
|
||||
VkImageTiling tiling;
|
||||
VkImageUsageFlags usage;
|
||||
qboolean has_alpha;
|
||||
qboolean is_cubemap;
|
||||
} xvk_image_create_t;
|
||||
|
||||
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create);
|
||||
void XVK_ImageDestroy(xvk_image_t *img);
|
|
@ -637,8 +637,8 @@ void VK_LightsAddEmissiveSurface( const struct vk_render_geometry_s *geom, const
|
|||
if (geom->material != kXVkMaterialSky && geom->material != kXVkMaterialEmissive) {
|
||||
VectorCopy(g_lights.map.emissive_textures[texture_num].emissive, esurf->emissive);
|
||||
} else {
|
||||
// TODO per-map sky emissive
|
||||
VectorSet(esurf->emissive, 1000.f, 1000.f, 1000.f);
|
||||
// TODO see #227
|
||||
VectorSet(esurf->emissive, 0.f, 0.f, 0.f);
|
||||
}
|
||||
Matrix3x4_Copy(esurf->transform, *transform_row);
|
||||
|
||||
|
|
|
@ -33,17 +33,10 @@ static int findTextureNamedLike( const char *texture_name ) {
|
|||
|
||||
return tex_id ? tex_id : -1;
|
||||
}
|
||||
static int loadTextureF( const char *fmt, ... ) {
|
||||
int tex_id = 0;
|
||||
char buffer[1024];
|
||||
va_list argptr;
|
||||
|
||||
va_start( argptr, fmt );
|
||||
vsnprintf( buffer, sizeof buffer, fmt, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
tex_id = VK_LoadTexture( buffer, NULL, 0, 0);
|
||||
gEngine.Con_Reportf("Loading texture %s => %d\n", buffer, tex_id);
|
||||
static int loadTexture( const char *filename, qboolean force_reload ) {
|
||||
const int tex_id = force_reload ? XVK_LoadTextureReplace( filename, NULL, 0, 0 ) : VK_LoadTexture( filename, NULL, 0, 0 );
|
||||
gEngine.Con_Reportf("Loading texture %s => %d\n", filename, tex_id);
|
||||
return tex_id ? tex_id : -1;
|
||||
}
|
||||
|
||||
|
@ -60,6 +53,9 @@ static void loadMaterialsFromFile( const char *filename ) {
|
|||
.normalmap = 0,
|
||||
};
|
||||
int current_material_index = -1;
|
||||
qboolean force_reload = false;
|
||||
|
||||
gEngine.Con_Reportf("Loading materials from %s\n", filename);
|
||||
|
||||
if ( !data )
|
||||
return;
|
||||
|
@ -85,6 +81,7 @@ static void loadMaterialsFromFile( const char *filename ) {
|
|||
.roughness = tglob.whiteTexture,
|
||||
.normalmap = 0,
|
||||
};
|
||||
force_reload = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -104,33 +101,57 @@ static void loadMaterialsFromFile( const char *filename ) {
|
|||
|
||||
if (Q_stricmp(key, "for") == 0) {
|
||||
current_material_index = findTextureNamedLike(value);
|
||||
} else if (Q_stricmp(key, "basecolor_map") == 0) {
|
||||
if ((current_material.base_color = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Failed to load basecolor_map texture %s\n", value);
|
||||
}
|
||||
} else if (Q_stricmp(key, "normal_map") == 0) {
|
||||
if ((current_material.normalmap = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Failed to load normal_map texture %s\n", value);
|
||||
current_material.normalmap = 0;
|
||||
}
|
||||
} else if (Q_stricmp(key, "metal_map") == 0) {
|
||||
if ((current_material.metalness = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Failed to load metal_map texture %s\n", value);
|
||||
current_material.metalness = tglob.blackTexture;
|
||||
}
|
||||
} else if (Q_stricmp(key, "roughness_map") == 0) {
|
||||
if ((current_material.roughness = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Failed to load roughness_map texture %s\n", value);
|
||||
current_material.roughness = tglob.whiteTexture;
|
||||
}
|
||||
} else if (Q_stricmp(key, "force_reload") == 0) {
|
||||
force_reload = Q_atoi(value) != 0;
|
||||
} else {
|
||||
gEngine.Con_Printf(S_ERROR "Unknown material key %s\n", key);
|
||||
char texture_path[256];
|
||||
int *tex_id_dest;
|
||||
int tex_id = -1;
|
||||
if (Q_stricmp(key, "basecolor_map") == 0) {
|
||||
tex_id_dest = ¤t_material.base_color;
|
||||
} else if (Q_stricmp(key, "normal_map") == 0) {
|
||||
tex_id_dest = ¤t_material.normalmap;
|
||||
} else if (Q_stricmp(key, "metal_map") == 0) {
|
||||
tex_id_dest = ¤t_material.metalness;
|
||||
} else if (Q_stricmp(key, "roughness_map") == 0) {
|
||||
tex_id_dest = ¤t_material.roughness;
|
||||
} else {
|
||||
gEngine.Con_Printf(S_ERROR "Unknown material key %s\n", key);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (value[0] == '/') {
|
||||
// Path relative to valve/pbr dir
|
||||
Q_snprintf(texture_path, sizeof(texture_path), "pbr%s", value);
|
||||
} else {
|
||||
// Path relative to current material.mat file
|
||||
Q_snprintf(texture_path, sizeof(texture_path), "%.*s%s", path_end - path_begin, path_begin, value);
|
||||
}
|
||||
|
||||
tex_id = loadTexture(texture_path, force_reload);
|
||||
if (tex_id < 0) {
|
||||
gEngine.Con_Printf(S_ERROR "Failed to load texture \"%s\" for key \"%s\"\n", value, key);
|
||||
continue;
|
||||
}
|
||||
|
||||
*tex_id_dest = tex_id;
|
||||
}
|
||||
}
|
||||
|
||||
Mem_Free( data );
|
||||
}
|
||||
|
||||
static void loadMaterialsFromFileF( const char *fmt, ... ) {
|
||||
char buffer[256];
|
||||
va_list argptr;
|
||||
|
||||
va_start( argptr, fmt );
|
||||
vsnprintf( buffer, sizeof buffer, fmt, argptr );
|
||||
va_end( argptr );
|
||||
|
||||
loadMaterialsFromFile( buffer );
|
||||
}
|
||||
|
||||
void XVK_ReloadMaterials( void ) {
|
||||
for (int i = 0; i < MAX_TEXTURES; ++i) {
|
||||
xvk_material_t *const mat = g_materials.materials + i;
|
||||
|
@ -149,7 +170,21 @@ void XVK_ReloadMaterials( void ) {
|
|||
}
|
||||
|
||||
loadMaterialsFromFile( "pbr/materials.mat" );
|
||||
// TODO map-specific
|
||||
loadMaterialsFromFile( "pbr/models/materials.mat" );
|
||||
|
||||
{
|
||||
const char *wad = g_map_entities.wadlist;
|
||||
for (; *wad;) {
|
||||
const char *const wad_end = Q_strchr(wad, ';');
|
||||
loadMaterialsFromFileF("pbr/%.*s/materials.mat", wad_end - wad, wad);
|
||||
wad = wad_end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const model_t *map = gEngine.pfnGetModelByIndex( 1 );
|
||||
loadMaterialsFromFileF("pbr/%s/materials.mat", map->name);
|
||||
}
|
||||
}
|
||||
|
||||
xvk_material_t* XVK_GetMaterialForTextureIndex( int tex_index ) {
|
||||
|
|
|
@ -136,7 +136,7 @@ void XVK_RayModel_Validate( void ) {
|
|||
const vk_kusok_data_t *kusok = kusochki + j;
|
||||
const vk_texture_t *tex = findTexture(kusok->tex_base_color);
|
||||
ASSERT(tex);
|
||||
ASSERT(tex->vk.image_view != VK_NULL_HANDLE);
|
||||
ASSERT(tex->vk.image.view != VK_NULL_HANDLE);
|
||||
|
||||
// uint32_t index_offset;
|
||||
// uint32_t vertex_offset;
|
||||
|
@ -217,6 +217,12 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) {
|
|||
kusochki[i].index_offset = mg->index_offset;
|
||||
kusochki[i].triangles = prim_count;
|
||||
|
||||
if (mg->material == kXVkMaterialSky) {
|
||||
kusochki[i].tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX;
|
||||
} else {
|
||||
kusochki[i].tex_base_color &= (~KUSOK_MATERIAL_FLAG_SKYBOX);
|
||||
}
|
||||
|
||||
//kusochki[i].texture = mg->texture;
|
||||
//kusochki[i].roughness = mg->material == kXVkMaterialWater ? 0. : 1.; // FIXME
|
||||
VectorSet(kusochki[i].emissive, 0, 0, 0 );
|
||||
|
@ -379,6 +385,10 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render
|
|||
kusok->tex_roughness = tglob.grayTexture;
|
||||
}
|
||||
|
||||
if (geom->material == kXVkMaterialSky) {
|
||||
kusok->tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX;
|
||||
}
|
||||
|
||||
Vector4Copy(color, kusok->color);
|
||||
|
||||
XVK_GetEmissiveForTexture( kusok->emissive, geom->texture );
|
||||
|
|
122
ref_vk/vk_rtx.c
122
ref_vk/vk_rtx.c
|
@ -31,6 +31,8 @@ enum {
|
|||
ShaderBindingTable_Hit,
|
||||
ShaderBindingTable_Hit_WithAlphaTest,
|
||||
ShaderBindingTable_Hit_Additive,
|
||||
ShaderBindingTable_Hit_Shadow,
|
||||
ShaderBindingTable_Hit__END = ShaderBindingTable_Hit_Shadow,
|
||||
|
||||
ShaderBindingTable_COUNT
|
||||
};
|
||||
|
@ -76,16 +78,18 @@ enum {
|
|||
RayDescBinding_Dest_ImageAdditive = 11,
|
||||
RayDescBinding_Dest_ImageNormals = 12,
|
||||
|
||||
RayDescBinding_SkyboxCube = 13,
|
||||
|
||||
RayDescBinding_COUNT
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
vk_image_t denoised;
|
||||
vk_image_t base_color;
|
||||
vk_image_t diffuse_gi;
|
||||
vk_image_t specular;
|
||||
vk_image_t additive;
|
||||
vk_image_t normals;
|
||||
xvk_image_t denoised;
|
||||
xvk_image_t base_color;
|
||||
xvk_image_t diffuse_gi;
|
||||
xvk_image_t specular;
|
||||
xvk_image_t additive;
|
||||
xvk_image_t normals;
|
||||
} xvk_ray_frame_images_t;
|
||||
|
||||
static struct {
|
||||
|
@ -351,6 +355,8 @@ static void createPipeline( void )
|
|||
uint32_t max_visible_surface_lights;
|
||||
float light_grid_cell_size;
|
||||
int max_light_clusters;
|
||||
uint32_t max_textures;
|
||||
uint32_t sbt_record_size;
|
||||
} spec_data = {
|
||||
.max_point_lights = MAX_POINT_LIGHTS,
|
||||
.max_emissive_kusochki = MAX_EMISSIVE_KUSOCHKI,
|
||||
|
@ -358,6 +364,8 @@ static void createPipeline( void )
|
|||
.max_visible_surface_lights = MAX_VISIBLE_SURFACE_LIGHTS,
|
||||
.light_grid_cell_size = LIGHT_GRID_CELL_SIZE,
|
||||
.max_light_clusters = MAX_LIGHT_CLUSTERS,
|
||||
.max_textures = MAX_TEXTURES,
|
||||
.sbt_record_size = g_rtx.sbt_record_size,
|
||||
};
|
||||
const VkSpecializationMapEntry spec_map[] = {
|
||||
{.constantID = 0, .offset = offsetof(struct RayShaderSpec, max_point_lights), .size = sizeof(int) },
|
||||
|
@ -366,6 +374,8 @@ static void createPipeline( void )
|
|||
{.constantID = 3, .offset = offsetof(struct RayShaderSpec, max_visible_surface_lights), .size = sizeof(uint32_t) },
|
||||
{.constantID = 4, .offset = offsetof(struct RayShaderSpec, light_grid_cell_size), .size = sizeof(float) },
|
||||
{.constantID = 5, .offset = offsetof(struct RayShaderSpec, max_light_clusters), .size = sizeof(int) },
|
||||
{.constantID = 6, .offset = offsetof(struct RayShaderSpec, max_textures), .size = sizeof(uint32_t) },
|
||||
{.constantID = 7, .offset = offsetof(struct RayShaderSpec, sbt_record_size), .size = sizeof(uint32_t) },
|
||||
};
|
||||
|
||||
VkSpecializationInfo spec = {
|
||||
|
@ -381,6 +391,7 @@ static void createPipeline( void )
|
|||
ShaderStageIndex_Miss_Shadow,
|
||||
ShaderStageIndex_Miss_Empty,
|
||||
ShaderStageIndex_ClosestHit,
|
||||
ShaderStageIndex_ClosestHit_Shadow,
|
||||
ShaderStageIndex_AnyHit_AlphaTest,
|
||||
ShaderStageIndex_AnyHit_Additive,
|
||||
ShaderStageIndex_COUNT,
|
||||
|
@ -414,6 +425,7 @@ static void createPipeline( void )
|
|||
DEFINE_SHADER("shadow.rmiss.spv", MISS, ShaderStageIndex_Miss_Shadow);
|
||||
DEFINE_SHADER("empty.rmiss.spv", MISS, ShaderStageIndex_Miss_Empty);
|
||||
DEFINE_SHADER("ray.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit);
|
||||
DEFINE_SHADER("shadow.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit_Shadow);
|
||||
DEFINE_SHADER("alphamask.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_AlphaTest);
|
||||
DEFINE_SHADER("additive.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_Additive);
|
||||
|
||||
|
@ -427,6 +439,7 @@ static void createPipeline( void )
|
|||
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit, SHADER_OFFSET_HIT_REGULAR);
|
||||
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_WithAlphaTest, SHADER_OFFSET_HIT_ALPHA_TEST);
|
||||
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Additive, SHADER_OFFSET_HIT_ADDITIVE);
|
||||
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Shadow, SHADER_OFFSET_HIT_SHADOW);
|
||||
|
||||
shader_groups[ShaderBindingTable_RayGen] = (VkRayTracingShaderGroupCreateInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR,
|
||||
|
@ -491,6 +504,15 @@ static void createPipeline( void )
|
|||
.intersectionShader = VK_SHADER_UNUSED_KHR,
|
||||
};
|
||||
|
||||
shader_groups[ShaderBindingTable_Hit_Shadow] = (VkRayTracingShaderGroupCreateInfoKHR) {
|
||||
.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR,
|
||||
.type = VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR,
|
||||
.anyHitShader = VK_SHADER_UNUSED_KHR,
|
||||
.closestHitShader = ShaderStageIndex_ClosestHit_Shadow,
|
||||
.generalShader = VK_SHADER_UNUSED_KHR,
|
||||
.intersectionShader = VK_SHADER_UNUSED_KHR,
|
||||
};
|
||||
|
||||
XVK_CHECK(vkCreateRayTracingPipelinesKHR(vk_core.device, VK_NULL_HANDLE, g_pipeline_cache, 1, &rtpci, NULL, &g_rtx.pipeline));
|
||||
ASSERT(g_rtx.pipeline != VK_NULL_HANDLE);
|
||||
|
||||
|
@ -613,12 +635,18 @@ 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);
|
||||
const qboolean exists = texture->vk.image_view != VK_NULL_HANDLE;
|
||||
const qboolean exists = texture->vk.image.view != VK_NULL_HANDLE;
|
||||
dii_all_textures[i].sampler = vk_core.default_sampler; // FIXME on AMD using pImmutableSamplers leads to NEAREST filtering ??. VK_NULL_HANDLE;
|
||||
dii_all_textures[i].imageView = exists ? texture->vk.image_view : findTexture(tglob.defaultTexture)->vk.image_view;
|
||||
dii_all_textures[i].imageView = exists ? texture->vk.image.view : findTexture(tglob.defaultTexture)->vk.image.view;
|
||||
ASSERT(dii_all_textures[i].imageView != VK_NULL_HANDLE);
|
||||
dii_all_textures[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
@ -731,7 +759,7 @@ LIST_GBUFFER_IMAGES(GBUFFER_WRITE_BARRIER)
|
|||
}
|
||||
const VkStridedDeviceAddressRegionKHR sbt_raygen = SBT_INDEX(ShaderBindingTable_RayGen, 1);
|
||||
const VkStridedDeviceAddressRegionKHR sbt_miss = SBT_INDEX(ShaderBindingTable_Miss, ShaderBindingTable_Miss_Empty - ShaderBindingTable_Miss);
|
||||
const VkStridedDeviceAddressRegionKHR sbt_hit = SBT_INDEX(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Additive - ShaderBindingTable_Hit);
|
||||
const VkStridedDeviceAddressRegionKHR sbt_hit = SBT_INDEX(ShaderBindingTable_Hit, ShaderBindingTable_Hit__END - ShaderBindingTable_Hit);
|
||||
const VkStridedDeviceAddressRegionKHR sbt_callable = { 0 };
|
||||
|
||||
vkCmdTraceRaysKHR(cmdbuf, &sbt_raygen, &sbt_miss, &sbt_hit, &sbt_callable, FRAME_WIDTH, FRAME_HEIGHT, 1 );
|
||||
|
@ -793,13 +821,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 +1169,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;
|
||||
|
||||
|
@ -1248,30 +1279,33 @@ qboolean VK_RayInit( void )
|
|||
createPipeline();
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
|
||||
g_rtx.frames[i].denoised = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT );
|
||||
SET_DEBUG_NAMEF(g_rtx.frames[i].denoised.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] denoised", i);
|
||||
|
||||
g_rtx.frames[i].base_color = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R8G8B8A8_UNORM,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
SET_DEBUG_NAMEF(g_rtx.frames[i].base_color.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] base_color", i);
|
||||
|
||||
g_rtx.frames[i].diffuse_gi = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
SET_DEBUG_NAMEF(g_rtx.frames[i].diffuse_gi.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] diffuse_gi", i);
|
||||
|
||||
g_rtx.frames[i].specular = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
SET_DEBUG_NAMEF(g_rtx.frames[i].specular.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] specular", i);
|
||||
|
||||
g_rtx.frames[i].additive = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
SET_DEBUG_NAMEF(g_rtx.frames[i].additive.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] additive", i);
|
||||
#define CREATE_GBUFFER_IMAGE(name, format_, add_usage_bits) \
|
||||
do { \
|
||||
char debug_name[64]; \
|
||||
const xvk_image_create_t create = { \
|
||||
.debug_name = debug_name, \
|
||||
.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); \
|
||||
} while(0)
|
||||
|
||||
CREATE_GBUFFER_IMAGE(denoised, VK_FORMAT_R16G16B16A16_SFLOAT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
CREATE_GBUFFER_IMAGE(base_color, VK_FORMAT_R8G8B8A8_UNORM, 0);
|
||||
CREATE_GBUFFER_IMAGE(diffuse_gi, VK_FORMAT_R16G16B16A16_SFLOAT, 0);
|
||||
CREATE_GBUFFER_IMAGE(specular, VK_FORMAT_R16G16B16A16_SFLOAT, 0);
|
||||
CREATE_GBUFFER_IMAGE(additive, VK_FORMAT_R16G16B16A16_SFLOAT, 0);
|
||||
// TODO make sure this format and usage is suppported
|
||||
g_rtx.frames[i].normals = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SNORM,
|
||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
||||
SET_DEBUG_NAMEF(g_rtx.frames[i].normals.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] normals", i);
|
||||
CREATE_GBUFFER_IMAGE(normals, VK_FORMAT_R16G16B16A16_SNORM, 0);
|
||||
#undef CREATE_GBUFFER_IMAGE
|
||||
}
|
||||
|
||||
if (vk_core.debug) {
|
||||
|
@ -1287,12 +1321,12 @@ void VK_RayShutdown( void ) {
|
|||
ASSERT(vk_core.rtx);
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
|
||||
VK_ImageDestroy(&g_rtx.frames[i].denoised);
|
||||
VK_ImageDestroy(&g_rtx.frames[i].base_color);
|
||||
VK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
|
||||
VK_ImageDestroy(&g_rtx.frames[i].specular);
|
||||
VK_ImageDestroy(&g_rtx.frames[i].additive);
|
||||
VK_ImageDestroy(&g_rtx.frames[i].normals);
|
||||
XVK_ImageDestroy(&g_rtx.frames[i].denoised);
|
||||
XVK_ImageDestroy(&g_rtx.frames[i].base_color);
|
||||
XVK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
|
||||
XVK_ImageDestroy(&g_rtx.frames[i].specular);
|
||||
XVK_ImageDestroy(&g_rtx.frames[i].additive);
|
||||
XVK_ImageDestroy(&g_rtx.frames[i].normals);
|
||||
}
|
||||
|
||||
vkDestroyPipeline(vk_core.device, g_rtx.pipeline, NULL);
|
||||
|
|
|
@ -48,11 +48,18 @@ void initTextures( void )
|
|||
*/
|
||||
}
|
||||
|
||||
static void unloadSkybox( void );
|
||||
|
||||
void destroyTextures( void )
|
||||
{
|
||||
for( unsigned int i = 0; i < vk_numTextures; i++ )
|
||||
VK_FreeTexture( i );
|
||||
|
||||
unloadSkybox();
|
||||
|
||||
XVK_ImageDestroy(&tglob.cubemap_placeholder.vk.image);
|
||||
memset(&tglob.cubemap_placeholder, 0, sizeof(tglob.cubemap_placeholder));
|
||||
|
||||
//memset( tglob.lightmapTextures, 0, sizeof( tglob.lightmapTextures ));
|
||||
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
|
||||
memset( vk_textures, 0, sizeof( vk_textures ));
|
||||
|
@ -230,6 +237,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 +299,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,63 +470,69 @@ static void BuildMipMap( byte *in, int srcWidth, int srcHeight, int srcDepth, in
|
|||
}
|
||||
}
|
||||
|
||||
static qboolean VK_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, num_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 );
|
||||
|
||||
// 1. Create VkImage w/ usage = DST|SAMPLED, layout=UNDEFINED
|
||||
{
|
||||
VkImageCreateInfo image_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.extent.width = pic->width,
|
||||
.extent.height = pic->height,
|
||||
.extent.depth = 1,
|
||||
const xvk_image_create_t create = {
|
||||
.debug_name = tex->name,
|
||||
.width = tex->width,
|
||||
.height = tex->height,
|
||||
.mips = mipCount,
|
||||
.layers = num_layers,
|
||||
.format = format,
|
||||
.mipLevels = mipCount,
|
||||
.arrayLayers = 1,
|
||||
.tiling = tiling,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.usage = usage,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.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,
|
||||
};
|
||||
XVK_CHECK(vkCreateImage(vk_core.device, &image_create_info, NULL, &tex->vk.image));
|
||||
SET_DEBUG_NAME(tex->vk.image, VK_OBJECT_TYPE_IMAGE, tex->name);
|
||||
}
|
||||
|
||||
// 2. Alloc mem for VkImage and bind it (DEV_LOCAL)
|
||||
{
|
||||
VkMemoryRequirements memreq;
|
||||
vkGetImageMemoryRequirements(vk_core.device, tex->vk.image, &memreq);
|
||||
tex->vk.device_memory = allocateDeviceMemory(memreq, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, 0);
|
||||
XVK_CHECK(vkBindImageMemory(vk_core.device, tex->vk.image, tex->vk.device_memory.device_memory, tex->vk.device_memory.offset));
|
||||
tex->vk.image = XVK_ImageCreate(&create);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -517,7 +548,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
|
|||
// 5.1.1 transitionToLayout(UNDEFINED -> DST)
|
||||
VkImageMemoryBarrier image_barrier = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.image = tex->vk.image,
|
||||
.image = tex->vk.image.image,
|
||||
.srcAccessMask = 0,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
|
@ -527,7 +558,7 @@ static qboolean VK_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));
|
||||
|
@ -537,9 +568,10 @@ static qboolean VK_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 );
|
||||
|
@ -551,7 +583,7 @@ static qboolean VK_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){
|
||||
|
@ -568,7 +600,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
|
|||
}
|
||||
|
||||
// TODO we could do this only once w/ region array
|
||||
vkCmdCopyBufferToImage(vk_core.cb_tex, vk_core.staging.buffer, tex->vk.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
vkCmdCopyBufferToImage(vk_core.cb_tex, vk_core.staging.buffer, tex->vk.image.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
staging_offset += mip_size;
|
||||
}
|
||||
|
@ -585,7 +617,7 @@ static qboolean VK_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,
|
||||
|
@ -603,28 +635,13 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
|
|||
XVK_CHECK(vkQueueWaitIdle(vk_core.queue));
|
||||
}
|
||||
|
||||
{
|
||||
VkImageViewCreateInfo ivci = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
ivci.format = format;
|
||||
ivci.image = tex->vk.image;
|
||||
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
ivci.subresourceRange.baseMipLevel = 0;
|
||||
ivci.subresourceRange.levelCount = mipCount;
|
||||
ivci.subresourceRange.baseArrayLayer = 0;
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
ivci.components = (VkComponentMapping){0, 0, 0, (pic->flags & IMAGE_HAS_ALPHA) ? 0 : VK_COMPONENT_SWIZZLE_ONE};
|
||||
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &tex->vk.image_view));
|
||||
SET_DEBUG_NAME(tex->vk.image_view, VK_OBJECT_TYPE_IMAGE_VIEW, tex->name);
|
||||
}
|
||||
|
||||
// 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 = {
|
||||
.imageView = tex->vk.image_view,
|
||||
.imageView = tex->vk.image.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
};
|
||||
VkWriteDescriptorSet wds[] = { {
|
||||
|
@ -707,7 +724,7 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
|||
// upload texture
|
||||
VK_ProcessImage( tex, pic );
|
||||
|
||||
if( !VK_UploadTexture( tex, pic ))
|
||||
if( !uploadTexture( tex, &pic, 1, false ))
|
||||
{
|
||||
memset( tex, 0, sizeof( vk_texture_t ));
|
||||
gEngine.FS_FreeImage( pic ); // release source texture
|
||||
|
@ -727,6 +744,19 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
|||
return tex - vk_textures;
|
||||
}
|
||||
|
||||
int XVK_LoadTextureReplace( const char *name, const byte *buf, size_t size, int flags ) {
|
||||
vk_texture_t *tex;
|
||||
if( !Common_CheckTexName( name ))
|
||||
return 0;
|
||||
|
||||
// free if already loaded
|
||||
if(( tex = Common_TextureForName( name ))) {
|
||||
VK_FreeTexture( tex - vk_textures );
|
||||
}
|
||||
|
||||
return VK_LoadTexture( name, buf, size, flags );
|
||||
}
|
||||
|
||||
int VK_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags )
|
||||
{
|
||||
gEngine.Con_Printf("VK FIXME: %s\n", __FUNCTION__);
|
||||
|
@ -756,7 +786,7 @@ void VK_FreeTexture( unsigned int texnum ) {
|
|||
ASSERT( tex != NULL );
|
||||
|
||||
// already freed?
|
||||
if( !tex->vk.image ) return;
|
||||
if( !tex->vk.image.image ) return;
|
||||
|
||||
// debug
|
||||
if( !tex->name[0] )
|
||||
|
@ -787,9 +817,7 @@ void VK_FreeTexture( unsigned int texnum ) {
|
|||
gEngine.FS_FreeImage( tex->original );
|
||||
*/
|
||||
|
||||
vkDestroyImageView(vk_core.device, tex->vk.image_view, NULL);
|
||||
vkDestroyImage(vk_core.device, tex->vk.image, NULL);
|
||||
freeDeviceMemory(&tex->vk.device_memory);
|
||||
XVK_ImageDestroy(&tex->vk.image);
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
}
|
||||
|
||||
|
@ -821,7 +849,7 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
|
|||
|
||||
VK_ProcessImage( tex, pic );
|
||||
|
||||
if( !VK_UploadTexture( tex, pic ))
|
||||
if( !uploadTexture( tex, &pic, 1, false ))
|
||||
{
|
||||
memset( tex, 0, sizeof( vk_texture_t ));
|
||||
return 0;
|
||||
|
@ -834,51 +862,6 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
|
|||
return (tex - vk_textures);
|
||||
}
|
||||
|
||||
vk_image_t VK_ImageCreate(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage) {
|
||||
vk_image_t image;
|
||||
VkMemoryRequirements memreq;
|
||||
VkImageViewCreateInfo ivci = {.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
|
||||
|
||||
VkImageCreateInfo ici = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.extent.width = width,
|
||||
.extent.height = height,
|
||||
.extent.depth = 1,
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.format = format,
|
||||
.tiling = tiling,
|
||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
.usage = usage,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
};
|
||||
|
||||
XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image));
|
||||
|
||||
vkGetImageMemoryRequirements(vk_core.device, image.image, &memreq);
|
||||
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.format = ici.format;
|
||||
ivci.image = image.image;
|
||||
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
ivci.subresourceRange.levelCount = 1;
|
||||
ivci.subresourceRange.layerCount = 1;
|
||||
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
void VK_ImageDestroy(vk_image_t *img) {
|
||||
vkDestroyImageView(vk_core.device, img->view, NULL);
|
||||
vkDestroyImage(vk_core.device, img->image, NULL);
|
||||
freeDeviceMemory(&img->devmem);
|
||||
*img = (vk_image_t){0};
|
||||
}
|
||||
|
||||
int XVK_TextureLookupF( const char *fmt, ...) {
|
||||
int tex_id = 0;
|
||||
char buffer[1024];
|
||||
|
@ -892,25 +875,26 @@ 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;
|
||||
}
|
||||
|
||||
static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
|
||||
//static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
|
||||
static struct {
|
||||
const char *suffix;
|
||||
uint flags;
|
||||
} g_skybox_info[6] = {
|
||||
{"rt", IMAGE_ROT_90},
|
||||
{"lf", IMAGE_FLIP_Y | IMAGE_ROT_90 | IMAGE_FLIP_X},
|
||||
{"bk", IMAGE_FLIP_Y},
|
||||
{"ft", IMAGE_FLIP_X},
|
||||
{"up", IMAGE_ROT_90},
|
||||
{"dn", IMAGE_ROT_90},
|
||||
};
|
||||
|
||||
#define SKYBOX_MISSED 0
|
||||
#define SKYBOX_HLSTYLE 1
|
||||
|
@ -929,7 +913,7 @@ static int CheckSkybox( const char *name )
|
|||
for( j = 0; j < 6; j++ )
|
||||
{
|
||||
// build side name
|
||||
sidename = va( "%s%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] );
|
||||
sidename = va( "%s%s.%s", name, g_skybox_info[j].suffix, skybox_ext[i] );
|
||||
if( gEngine.FS_FileExists( sidename, false ))
|
||||
num_checked_sides++;
|
||||
|
||||
|
@ -941,7 +925,7 @@ static int CheckSkybox( const char *name )
|
|||
for( j = 0; j < 6; j++ )
|
||||
{
|
||||
// build side name
|
||||
sidename = va( "%s_%s.%s", name, r_skyBoxSuffix[j], skybox_ext[i] );
|
||||
sidename = va( "%s_%s.%s", name, g_skybox_info[j].suffix, skybox_ext[i] );
|
||||
if( gEngine.FS_FileExists( sidename, false ))
|
||||
num_checked_sides++;
|
||||
}
|
||||
|
@ -958,6 +942,8 @@ void XVK_SetupSky( const char *skyboxname )
|
|||
char loadname[MAX_STRING];
|
||||
char sidename[MAX_STRING];
|
||||
int i, result, len;
|
||||
rgbdata_t *sides[6];
|
||||
qboolean success = false;
|
||||
|
||||
if( !COM_CheckString( skyboxname ))
|
||||
{
|
||||
|
@ -990,21 +976,43 @@ void XVK_SetupSky( const char *skyboxname )
|
|||
for( i = 0; i < 6; i++ )
|
||||
{
|
||||
if( result == SKYBOX_HLSTYLE )
|
||||
Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, r_skyBoxSuffix[i] );
|
||||
else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, r_skyBoxSuffix[i] );
|
||||
Q_snprintf( sidename, sizeof( sidename ), "%s%s", loadname, g_skybox_info[i].suffix );
|
||||
else Q_snprintf( sidename, sizeof( sidename ), "%s_%s", loadname, g_skybox_info[i].suffix );
|
||||
|
||||
tglob.skyboxTextures[i] = VK_LoadTexture( sidename, NULL, 0, TF_CLAMP|TF_SKY );
|
||||
if( !tglob.skyboxTextures[i] ) break;
|
||||
gEngine.Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " );
|
||||
sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0);
|
||||
if (!sides[i] || !sides[i]->buffer)
|
||||
break;
|
||||
|
||||
|
||||
{
|
||||
uint img_flags = g_skybox_info[i].flags;
|
||||
// we need to expand image into RGBA buffer
|
||||
if( sides[i]->type == PF_INDEXED_24 || sides[i]->type == PF_INDEXED_32 )
|
||||
img_flags |= IMAGE_FORCE_RGBA;
|
||||
gEngine.Image_Process( &sides[i], 0, 0, img_flags, 0.f );
|
||||
}
|
||||
gEngine.Con_DPrintf( "%s%s%s", skyboxname, g_skybox_info[i].suffix, i != 5 ? ", " : ". " );
|
||||
}
|
||||
|
||||
if( i == 6 )
|
||||
{
|
||||
if( i != 6 )
|
||||
goto cleanup;
|
||||
|
||||
if( !Common_CheckTexName( loadname ))
|
||||
goto cleanup;
|
||||
|
||||
Q_strncpy( tglob.skybox_cube.name, loadname, sizeof( tglob.skybox_cube.name ));
|
||||
success = uploadTexture(&tglob.skybox_cube, sides, 6, true);
|
||||
|
||||
cleanup:
|
||||
for (int j = 0; j < i; ++j)
|
||||
gEngine.FS_FreeImage( sides[j] ); // release source texture
|
||||
|
||||
if (success) {
|
||||
tglob.fCustomSkybox = true;
|
||||
gEngine.Con_DPrintf( "done\n" );
|
||||
return; // loaded
|
||||
} else {
|
||||
tglob.skybox_cube.name[0] = '\0';
|
||||
gEngine.Con_DPrintf( "^2failed\n" );
|
||||
unloadSkybox();
|
||||
}
|
||||
|
||||
gEngine.Con_DPrintf( "^2failed\n" );
|
||||
unloadSkybox();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "vk_core.h"
|
||||
#include "vk_image.h"
|
||||
|
||||
#include "xash3d_types.h"
|
||||
#include "const.h"
|
||||
|
@ -14,9 +15,7 @@ typedef struct vk_texture_s
|
|||
uint texnum;
|
||||
|
||||
struct {
|
||||
VkImage image;
|
||||
VkImageView image_view;
|
||||
device_memory_t device_memory;
|
||||
xvk_image_t image;
|
||||
VkDescriptorSet descriptor;
|
||||
} vk;
|
||||
|
||||
|
@ -37,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
|
||||
|
@ -65,19 +66,10 @@ int VK_CreateTextureArray( const char *name, int width, int height, int depth,
|
|||
void VK_FreeTexture( unsigned int texnum );
|
||||
int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
|
||||
|
||||
int XVK_LoadTextureReplace( const char *name, const byte *buf, size_t size, int flags );
|
||||
|
||||
int XVK_TextureLookupF( const char *fmt, ...);
|
||||
|
||||
#define VK_LoadTextureInternal( name, pic, flags ) VK_LoadTextureFromBuffer( name, pic, flags, false )
|
||||
|
||||
void XVK_SetupSky( const char *skyboxname );
|
||||
|
||||
typedef struct {
|
||||
// FIXME better memory allocation
|
||||
// OCHEN PLOHO
|
||||
device_memory_t devmem;
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
} vk_image_t;
|
||||
|
||||
vk_image_t VK_ImageCreate(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage);
|
||||
void VK_ImageDestroy(vk_image_t *img);
|
||||
|
|
Loading…
Reference in New Issue