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 (constant_id = 6) const uint MAX_TEXTURES = 4096;
|
||||||
layout (set = 0, binding = 6) uniform sampler2D textures[MAX_TEXTURES];
|
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;
|
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 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 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 n1 = vertices[vi1].normal;
|
||||||
const vec3 n2 = vertices[vi2].normal;
|
const vec3 n2 = vertices[vi2].normal;
|
||||||
const vec3 n3 = vertices[vi3].normal;
|
const vec3 n3 = vertices[vi3].normal;
|
||||||
|
@ -94,11 +119,6 @@ void main() {
|
||||||
vertices[vi3].gl_tc,
|
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_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;
|
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 float geom_normal_sign = sign(dot(real_geom_normal, -gl_WorldRayDirectionEXT));
|
||||||
const vec3 geom_normal = geom_normal_sign * real_geom_normal;
|
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;
|
const float ray_cone_width = payload.pixel_cone_spread_angle * payload.t_offset;
|
||||||
vec4 uv_lods;
|
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);
|
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 vec4 tex_color = sampleTexture(tex_index, texture_uv, uv_lods);
|
||||||
//const vec3 base_color = pow(tex_color.rgb, vec3(2.));
|
//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.));
|
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
|
// 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.base_color = base_color * kusochki[kusok_index].color.rgb;
|
||||||
payload.transmissiveness = (1. - tex_color.a * kusochki[kusok_index].color.a);
|
payload.transmissiveness = (1. - tex_color.a * kusochki[kusok_index].color.a);
|
||||||
payload.normal = normal;
|
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 = 4) const float LIGHT_GRID_CELL_SIZE = 256.;
|
||||||
layout (constant_id = 5) const uint MAX_LIGHT_CLUSTERS = 32768;
|
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_SIZE = 2 + MAX_VISIBLE_POINT_LIGHTS + MAX_VISIBLE_SURFACE_LIGHTS;
|
||||||
//const uint LIGHT_CLUSTER_NUM_DLIGHTS_OFFSET = 0;
|
//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;
|
layout(location = PAYLOAD_LOCATION_ADDITIVE) rayPayloadEXT RayPayloadAdditive payload_additive;
|
||||||
|
|
||||||
bool shadowed(vec3 pos, vec3 dir, float dist) {
|
bool shadowed(vec3 pos, vec3 dir, float dist) {
|
||||||
payload_shadow.shadow = true;
|
payload_shadow.hit_type = SHADOW_HIT;
|
||||||
const uint flags = 0
|
const uint flags = 0
|
||||||
//| gl_RayFlagsCullFrontFacingTrianglesEXT
|
//| gl_RayFlagsCullFrontFacingTrianglesEXT
|
||||||
//| gl_RayFlagsOpaqueEXT
|
//| gl_RayFlagsOpaqueEXT
|
||||||
|
@ -63,7 +64,24 @@ bool shadowed(vec3 pos, vec3 dir, float dist) {
|
||||||
GEOMETRY_BIT_OPAQUE,
|
GEOMETRY_BIT_OPAQUE,
|
||||||
0, 0, SHADER_OFFSET_MISS_SHADOW,
|
0, 0, SHADER_OFFSET_MISS_SHADOW,
|
||||||
pos, 0., dir, dist - shadow_offset_fudge, PAYLOAD_LOCATION_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)
|
// 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 float stopdot = lights.point_lights[i].color_stopdot.a;
|
||||||
const vec3 dir = lights.point_lights[i].dir_stopdot2.xyz;
|
const vec3 dir = lights.point_lights[i].dir_stopdot2.xyz;
|
||||||
const float stopdot2 = lights.point_lights[i].dir_stopdot2.a;
|
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 vec3 light_dir_norm = normalize(light_dir);
|
||||||
const float light_dot = dot(light_dir_norm, payload_opaque.normal);
|
const float light_dot = dot(light_dir_norm, payload_opaque.normal);
|
||||||
if (light_dot < 1e-5)
|
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);
|
spot_attenuation = (spot_dot - stopdot2) / (stopdot - stopdot2);
|
||||||
|
|
||||||
float fdist = 1.f;
|
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?
|
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 (environment) {
|
if (not_environment) {
|
||||||
#if 1
|
#if 1
|
||||||
const float d2 = dot(light_dir, light_dir);
|
const float d2 = dot(light_dir, light_dir);
|
||||||
const float r2 = origin_r.w * origin_r.w;
|
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)
|
// if (dot(color,color) < color_culling_threshold)
|
||||||
// continue;
|
// continue;
|
||||||
|
|
||||||
// TODO split into diffuse and specular for denoiser
|
|
||||||
vec3 ldiffuse, lspecular;
|
vec3 ldiffuse, lspecular;
|
||||||
evalSplitBRDF(payload_opaque.normal, light_dir_norm, view_dir, material, ldiffuse, lspecular);
|
evalSplitBRDF(payload_opaque.normal, light_dir_norm, view_dir, material, ldiffuse, lspecular);
|
||||||
ldiffuse *= color;
|
ldiffuse *= color;
|
||||||
|
@ -232,9 +249,14 @@ void computePointLights(uint cluster_index, vec3 throughput, vec3 view_dir, Mate
|
||||||
if (dot(combined,combined) < color_culling_threshold)
|
if (dot(combined,combined) < color_culling_threshold)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// TODO for environment light check that we've hit SURF_SKY
|
if (not_environment) {
|
||||||
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
if (shadowed(payload_opaque.hit_pos_t.xyz, light_dir_norm, light_dist + shadow_offset_fudge))
|
||||||
continue;
|
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;
|
diffuse += ldiffuse;
|
||||||
specular += lspecular;
|
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);
|
vec3 additive = traceAdditive(origin, direction, payload_opaque.hit_pos_t.w <= 0. ? L : payload_opaque.hit_pos_t.w);
|
||||||
|
|
||||||
// Sky/envmap
|
// Sky/envmap
|
||||||
if (payload_opaque.hit_pos_t.w <= 0.) {
|
if (payload_opaque.kusok_index < 0) {
|
||||||
if (bounce == 0) {
|
if (bounce == 0) {
|
||||||
out_additive += payload_opaque.emissive * color_factor + additive;
|
out_additive += payload_opaque.emissive * color_factor + additive;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,14 +1,9 @@
|
||||||
#version 460 core
|
#version 460 core
|
||||||
#extension GL_EXT_nonuniform_qualifier : enable
|
|
||||||
#extension GL_GOOGLE_include_directive : require
|
#extension GL_GOOGLE_include_directive : require
|
||||||
|
|
||||||
#include "ray_common.glsl"
|
#include "ray_common.glsl"
|
||||||
#include "ray_kusochki.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;
|
layout(location = PAYLOAD_LOCATION_OPAQUE) rayPayloadInEXT RayPayloadOpaque payload;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -20,8 +15,4 @@ void main() {
|
||||||
payload.kusok_index = -1;
|
payload.kusok_index = -1;
|
||||||
payload.material_index = 0;
|
payload.material_index = 0;
|
||||||
payload.emissive = vec3(1., 0., 1.);
|
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;
|
vec4 debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define SHADOW_MISS 0
|
||||||
|
#define SHADOW_HIT 1
|
||||||
|
#define SHADOW_SKY 2
|
||||||
|
|
||||||
struct RayPayloadShadow {
|
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_REGULAR 0
|
||||||
#define SHADER_OFFSET_HIT_ALPHA_TEST 1
|
#define SHADER_OFFSET_HIT_ALPHA_TEST 1
|
||||||
#define SHADER_OFFSET_HIT_ADDITIVE 2
|
#define SHADER_OFFSET_HIT_ADDITIVE 2
|
||||||
|
#define SHADER_OFFSET_HIT_SHADOW 3
|
||||||
|
|
||||||
|
#define KUSOK_MATERIAL_FLAG_SKYBOX 0x80000000
|
||||||
|
|
||||||
struct Kusok {
|
struct Kusok {
|
||||||
uint index_offset;
|
uint index_offset;
|
||||||
|
@ -71,7 +74,7 @@ struct EmissiveKusok {
|
||||||
struct Lights {
|
struct Lights {
|
||||||
uint num_kusochki;
|
uint num_kusochki;
|
||||||
uint num_point_lights;
|
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 EmissiveKusok kusochki[MAX_EMISSIVE_KUSOCHKI];
|
||||||
STRUCT PointLight point_lights[MAX_POINT_LIGHTS];
|
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;
|
layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payload_shadow;
|
||||||
|
|
||||||
void main() {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Explicitly enable SURF_SKY, otherwise they will be skipped by SURF_DRAWTILED
|
||||||
if( FBitSet( surf->flags, SURF_DRAWSKY )) {
|
if( FBitSet( surf->flags, SURF_DRAWSKY )) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if( FBitSet( surf->flags, SURF_DRAWTILED )) {
|
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;
|
const msurface_t *surf = mod->surfaces + mod->firstmodelsurface + i;
|
||||||
|
|
||||||
sizes.water_surfaces += !!(surf->flags & (SURF_DRAWTURB | SURF_DRAWTURB_QUADS));
|
sizes.water_surfaces += !!(surf->flags & (SURF_DRAWTURB | SURF_DRAWTURB_QUADS));
|
||||||
//sizes.sky_surfaces += !!(surf->flags & SURF_DRAWSKY);
|
|
||||||
|
|
||||||
if (!renderableSurface(surf, i))
|
if (!renderableSurface(surf, i))
|
||||||
continue;
|
continue;
|
||||||
|
@ -487,7 +487,9 @@ static qboolean loadBrushSurfaces( model_sizes_t sizes, const model_t *mod ) {
|
||||||
model_geometry->material = kXVkMaterialSky;
|
model_geometry->material = kXVkMaterialSky;
|
||||||
} else {
|
} else {
|
||||||
model_geometry->material = kXVkMaterialRegular;
|
model_geometry->material = kXVkMaterialRegular;
|
||||||
VK_CreateSurfaceLightmap( surf, mod );
|
if (!FBitSet( surf->flags, SURF_DRAWTILED )) {
|
||||||
|
VK_CreateSurfaceLightmap( surf, mod );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FBitSet( surf->flags, SURF_CONVEYOR )) {
|
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) {
|
if (geom->material != kXVkMaterialSky && geom->material != kXVkMaterialEmissive) {
|
||||||
VectorCopy(g_lights.map.emissive_textures[texture_num].emissive, esurf->emissive);
|
VectorCopy(g_lights.map.emissive_textures[texture_num].emissive, esurf->emissive);
|
||||||
} else {
|
} else {
|
||||||
// TODO per-map sky emissive
|
// TODO see #227
|
||||||
VectorSet(esurf->emissive, 1000.f, 1000.f, 1000.f);
|
VectorSet(esurf->emissive, 0.f, 0.f, 0.f);
|
||||||
}
|
}
|
||||||
Matrix3x4_Copy(esurf->transform, *transform_row);
|
Matrix3x4_Copy(esurf->transform, *transform_row);
|
||||||
|
|
||||||
|
|
|
@ -33,17 +33,10 @@ static int findTextureNamedLike( const char *texture_name ) {
|
||||||
|
|
||||||
return tex_id ? tex_id : -1;
|
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 );
|
static int loadTexture( const char *filename, qboolean force_reload ) {
|
||||||
vsnprintf( buffer, sizeof buffer, fmt, argptr );
|
const int tex_id = force_reload ? XVK_LoadTextureReplace( filename, NULL, 0, 0 ) : VK_LoadTexture( filename, NULL, 0, 0 );
|
||||||
va_end( argptr );
|
gEngine.Con_Reportf("Loading texture %s => %d\n", filename, tex_id);
|
||||||
|
|
||||||
tex_id = VK_LoadTexture( buffer, NULL, 0, 0);
|
|
||||||
gEngine.Con_Reportf("Loading texture %s => %d\n", buffer, tex_id);
|
|
||||||
return tex_id ? tex_id : -1;
|
return tex_id ? tex_id : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +53,9 @@ static void loadMaterialsFromFile( const char *filename ) {
|
||||||
.normalmap = 0,
|
.normalmap = 0,
|
||||||
};
|
};
|
||||||
int current_material_index = -1;
|
int current_material_index = -1;
|
||||||
|
qboolean force_reload = false;
|
||||||
|
|
||||||
|
gEngine.Con_Reportf("Loading materials from %s\n", filename);
|
||||||
|
|
||||||
if ( !data )
|
if ( !data )
|
||||||
return;
|
return;
|
||||||
|
@ -85,6 +81,7 @@ static void loadMaterialsFromFile( const char *filename ) {
|
||||||
.roughness = tglob.whiteTexture,
|
.roughness = tglob.whiteTexture,
|
||||||
.normalmap = 0,
|
.normalmap = 0,
|
||||||
};
|
};
|
||||||
|
force_reload = false;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,33 +101,57 @@ static void loadMaterialsFromFile( const char *filename ) {
|
||||||
|
|
||||||
if (Q_stricmp(key, "for") == 0) {
|
if (Q_stricmp(key, "for") == 0) {
|
||||||
current_material_index = findTextureNamedLike(value);
|
current_material_index = findTextureNamedLike(value);
|
||||||
} else if (Q_stricmp(key, "basecolor_map") == 0) {
|
} else if (Q_stricmp(key, "force_reload") == 0) {
|
||||||
if ((current_material.base_color = loadTextureF("%.*s%s", path_end - path_begin, path_begin, value)) < 0) {
|
force_reload = Q_atoi(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 {
|
} 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 );
|
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 ) {
|
void XVK_ReloadMaterials( void ) {
|
||||||
for (int i = 0; i < MAX_TEXTURES; ++i) {
|
for (int i = 0; i < MAX_TEXTURES; ++i) {
|
||||||
xvk_material_t *const mat = g_materials.materials + i;
|
xvk_material_t *const mat = g_materials.materials + i;
|
||||||
|
@ -149,7 +170,21 @@ void XVK_ReloadMaterials( void ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadMaterialsFromFile( "pbr/materials.mat" );
|
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 ) {
|
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_kusok_data_t *kusok = kusochki + j;
|
||||||
const vk_texture_t *tex = findTexture(kusok->tex_base_color);
|
const vk_texture_t *tex = findTexture(kusok->tex_base_color);
|
||||||
ASSERT(tex);
|
ASSERT(tex);
|
||||||
ASSERT(tex->vk.image_view != VK_NULL_HANDLE);
|
ASSERT(tex->vk.image.view != VK_NULL_HANDLE);
|
||||||
|
|
||||||
// uint32_t index_offset;
|
// uint32_t index_offset;
|
||||||
// uint32_t vertex_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].index_offset = mg->index_offset;
|
||||||
kusochki[i].triangles = prim_count;
|
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].texture = mg->texture;
|
||||||
//kusochki[i].roughness = mg->material == kXVkMaterialWater ? 0. : 1.; // FIXME
|
//kusochki[i].roughness = mg->material == kXVkMaterialWater ? 0. : 1.; // FIXME
|
||||||
VectorSet(kusochki[i].emissive, 0, 0, 0 );
|
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;
|
kusok->tex_roughness = tglob.grayTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (geom->material == kXVkMaterialSky) {
|
||||||
|
kusok->tex_base_color |= KUSOK_MATERIAL_FLAG_SKYBOX;
|
||||||
|
}
|
||||||
|
|
||||||
Vector4Copy(color, kusok->color);
|
Vector4Copy(color, kusok->color);
|
||||||
|
|
||||||
XVK_GetEmissiveForTexture( kusok->emissive, geom->texture );
|
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,
|
||||||
ShaderBindingTable_Hit_WithAlphaTest,
|
ShaderBindingTable_Hit_WithAlphaTest,
|
||||||
ShaderBindingTable_Hit_Additive,
|
ShaderBindingTable_Hit_Additive,
|
||||||
|
ShaderBindingTable_Hit_Shadow,
|
||||||
|
ShaderBindingTable_Hit__END = ShaderBindingTable_Hit_Shadow,
|
||||||
|
|
||||||
ShaderBindingTable_COUNT
|
ShaderBindingTable_COUNT
|
||||||
};
|
};
|
||||||
|
@ -76,16 +78,18 @@ enum {
|
||||||
RayDescBinding_Dest_ImageAdditive = 11,
|
RayDescBinding_Dest_ImageAdditive = 11,
|
||||||
RayDescBinding_Dest_ImageNormals = 12,
|
RayDescBinding_Dest_ImageNormals = 12,
|
||||||
|
|
||||||
|
RayDescBinding_SkyboxCube = 13,
|
||||||
|
|
||||||
RayDescBinding_COUNT
|
RayDescBinding_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
vk_image_t denoised;
|
xvk_image_t denoised;
|
||||||
vk_image_t base_color;
|
xvk_image_t base_color;
|
||||||
vk_image_t diffuse_gi;
|
xvk_image_t diffuse_gi;
|
||||||
vk_image_t specular;
|
xvk_image_t specular;
|
||||||
vk_image_t additive;
|
xvk_image_t additive;
|
||||||
vk_image_t normals;
|
xvk_image_t normals;
|
||||||
} xvk_ray_frame_images_t;
|
} xvk_ray_frame_images_t;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -351,6 +355,8 @@ static void createPipeline( void )
|
||||||
uint32_t max_visible_surface_lights;
|
uint32_t max_visible_surface_lights;
|
||||||
float light_grid_cell_size;
|
float light_grid_cell_size;
|
||||||
int max_light_clusters;
|
int max_light_clusters;
|
||||||
|
uint32_t max_textures;
|
||||||
|
uint32_t sbt_record_size;
|
||||||
} spec_data = {
|
} spec_data = {
|
||||||
.max_point_lights = MAX_POINT_LIGHTS,
|
.max_point_lights = MAX_POINT_LIGHTS,
|
||||||
.max_emissive_kusochki = MAX_EMISSIVE_KUSOCHKI,
|
.max_emissive_kusochki = MAX_EMISSIVE_KUSOCHKI,
|
||||||
|
@ -358,6 +364,8 @@ static void createPipeline( void )
|
||||||
.max_visible_surface_lights = MAX_VISIBLE_SURFACE_LIGHTS,
|
.max_visible_surface_lights = MAX_VISIBLE_SURFACE_LIGHTS,
|
||||||
.light_grid_cell_size = LIGHT_GRID_CELL_SIZE,
|
.light_grid_cell_size = LIGHT_GRID_CELL_SIZE,
|
||||||
.max_light_clusters = MAX_LIGHT_CLUSTERS,
|
.max_light_clusters = MAX_LIGHT_CLUSTERS,
|
||||||
|
.max_textures = MAX_TEXTURES,
|
||||||
|
.sbt_record_size = g_rtx.sbt_record_size,
|
||||||
};
|
};
|
||||||
const VkSpecializationMapEntry spec_map[] = {
|
const VkSpecializationMapEntry spec_map[] = {
|
||||||
{.constantID = 0, .offset = offsetof(struct RayShaderSpec, max_point_lights), .size = sizeof(int) },
|
{.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 = 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 = 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 = 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 = {
|
VkSpecializationInfo spec = {
|
||||||
|
@ -381,6 +391,7 @@ static void createPipeline( void )
|
||||||
ShaderStageIndex_Miss_Shadow,
|
ShaderStageIndex_Miss_Shadow,
|
||||||
ShaderStageIndex_Miss_Empty,
|
ShaderStageIndex_Miss_Empty,
|
||||||
ShaderStageIndex_ClosestHit,
|
ShaderStageIndex_ClosestHit,
|
||||||
|
ShaderStageIndex_ClosestHit_Shadow,
|
||||||
ShaderStageIndex_AnyHit_AlphaTest,
|
ShaderStageIndex_AnyHit_AlphaTest,
|
||||||
ShaderStageIndex_AnyHit_Additive,
|
ShaderStageIndex_AnyHit_Additive,
|
||||||
ShaderStageIndex_COUNT,
|
ShaderStageIndex_COUNT,
|
||||||
|
@ -414,6 +425,7 @@ static void createPipeline( void )
|
||||||
DEFINE_SHADER("shadow.rmiss.spv", MISS, ShaderStageIndex_Miss_Shadow);
|
DEFINE_SHADER("shadow.rmiss.spv", MISS, ShaderStageIndex_Miss_Shadow);
|
||||||
DEFINE_SHADER("empty.rmiss.spv", MISS, ShaderStageIndex_Miss_Empty);
|
DEFINE_SHADER("empty.rmiss.spv", MISS, ShaderStageIndex_Miss_Empty);
|
||||||
DEFINE_SHADER("ray.rchit.spv", CLOSEST_HIT, ShaderStageIndex_ClosestHit);
|
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("alphamask.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_AlphaTest);
|
||||||
DEFINE_SHADER("additive.rahit.spv", ANY_HIT, ShaderStageIndex_AnyHit_Additive);
|
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, SHADER_OFFSET_HIT_REGULAR);
|
||||||
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_WithAlphaTest, SHADER_OFFSET_HIT_ALPHA_TEST);
|
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_Additive, SHADER_OFFSET_HIT_ADDITIVE);
|
||||||
|
ASSERT_SHADER_OFFSET(ShaderBindingTable_Hit, ShaderBindingTable_Hit_Shadow, SHADER_OFFSET_HIT_SHADOW);
|
||||||
|
|
||||||
shader_groups[ShaderBindingTable_RayGen] = (VkRayTracingShaderGroupCreateInfoKHR) {
|
shader_groups[ShaderBindingTable_RayGen] = (VkRayTracingShaderGroupCreateInfoKHR) {
|
||||||
.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR,
|
||||||
|
@ -491,6 +504,15 @@ static void createPipeline( void )
|
||||||
.intersectionShader = VK_SHADER_UNUSED_KHR,
|
.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));
|
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);
|
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_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
|
// TODO: move this to vk_texture.c
|
||||||
for (int i = 0; i < MAX_TEXTURES; ++i) {
|
for (int i = 0; i < MAX_TEXTURES; ++i) {
|
||||||
const vk_texture_t *texture = findTexture(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].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);
|
ASSERT(dii_all_textures[i].imageView != VK_NULL_HANDLE);
|
||||||
dii_all_textures[i].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
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_raygen = SBT_INDEX(ShaderBindingTable_RayGen, 1);
|
||||||
const VkStridedDeviceAddressRegionKHR sbt_miss = SBT_INDEX(ShaderBindingTable_Miss, ShaderBindingTable_Miss_Empty - ShaderBindingTable_Miss);
|
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 };
|
const VkStridedDeviceAddressRegionKHR sbt_callable = { 0 };
|
||||||
|
|
||||||
vkCmdTraceRaysKHR(cmdbuf, &sbt_raygen, &sbt_miss, &sbt_hit, &sbt_callable, FRAME_WIDTH, FRAME_HEIGHT, 1 );
|
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);
|
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,
|
.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)
|
// for (int i = 0; i < ARRAYSIZE(samplers); ++i)
|
||||||
// samplers[i] = vk_core.default_sampler;
|
// samplers[i] = vk_core.default_sampler;
|
||||||
|
|
||||||
|
@ -1248,30 +1279,33 @@ qboolean VK_RayInit( void )
|
||||||
createPipeline();
|
createPipeline();
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
|
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,
|
#define CREATE_GBUFFER_IMAGE(name, format_, add_usage_bits) \
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT );
|
do { \
|
||||||
SET_DEBUG_NAMEF(g_rtx.frames[i].denoised.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] denoised", i);
|
char debug_name[64]; \
|
||||||
|
const xvk_image_create_t create = { \
|
||||||
g_rtx.frames[i].base_color = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R8G8B8A8_UNORM,
|
.debug_name = debug_name, \
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
.width = FRAME_WIDTH, \
|
||||||
SET_DEBUG_NAMEF(g_rtx.frames[i].base_color.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] base_color", i);
|
.height = FRAME_HEIGHT, \
|
||||||
|
.mips = 1, \
|
||||||
g_rtx.frames[i].diffuse_gi = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
.layers = 1, \
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
.format = format_, \
|
||||||
SET_DEBUG_NAMEF(g_rtx.frames[i].diffuse_gi.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] diffuse_gi", i);
|
.tiling = VK_IMAGE_TILING_OPTIMAL, \
|
||||||
|
.usage = VK_IMAGE_USAGE_STORAGE_BIT | add_usage_bits, \
|
||||||
g_rtx.frames[i].specular = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
.has_alpha = true, \
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
.is_cubemap = false, \
|
||||||
SET_DEBUG_NAMEF(g_rtx.frames[i].specular.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] specular", i);
|
}; \
|
||||||
|
Q_snprintf(debug_name, sizeof(debug_name), "rtx frames[%d] " # name, i); \
|
||||||
g_rtx.frames[i].additive = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SFLOAT,
|
g_rtx.frames[i].name = XVK_ImageCreate(&create); \
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
} while(0)
|
||||||
SET_DEBUG_NAMEF(g_rtx.frames[i].additive.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] additive", i);
|
|
||||||
|
|
||||||
|
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
|
// TODO make sure this format and usage is suppported
|
||||||
g_rtx.frames[i].normals = VK_ImageCreate(FRAME_WIDTH, FRAME_HEIGHT, VK_FORMAT_R16G16B16A16_SNORM,
|
CREATE_GBUFFER_IMAGE(normals, VK_FORMAT_R16G16B16A16_SNORM, 0);
|
||||||
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_STORAGE_BIT);
|
#undef CREATE_GBUFFER_IMAGE
|
||||||
SET_DEBUG_NAMEF(g_rtx.frames[i].normals.image, VK_OBJECT_TYPE_IMAGE, "rtx frames[%d] normals", i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vk_core.debug) {
|
if (vk_core.debug) {
|
||||||
|
@ -1287,12 +1321,12 @@ void VK_RayShutdown( void ) {
|
||||||
ASSERT(vk_core.rtx);
|
ASSERT(vk_core.rtx);
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
|
for (int i = 0; i < ARRAYSIZE(g_rtx.frames); ++i) {
|
||||||
VK_ImageDestroy(&g_rtx.frames[i].denoised);
|
XVK_ImageDestroy(&g_rtx.frames[i].denoised);
|
||||||
VK_ImageDestroy(&g_rtx.frames[i].base_color);
|
XVK_ImageDestroy(&g_rtx.frames[i].base_color);
|
||||||
VK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
|
XVK_ImageDestroy(&g_rtx.frames[i].diffuse_gi);
|
||||||
VK_ImageDestroy(&g_rtx.frames[i].specular);
|
XVK_ImageDestroy(&g_rtx.frames[i].specular);
|
||||||
VK_ImageDestroy(&g_rtx.frames[i].additive);
|
XVK_ImageDestroy(&g_rtx.frames[i].additive);
|
||||||
VK_ImageDestroy(&g_rtx.frames[i].normals);
|
XVK_ImageDestroy(&g_rtx.frames[i].normals);
|
||||||
}
|
}
|
||||||
|
|
||||||
vkDestroyPipeline(vk_core.device, g_rtx.pipeline, NULL);
|
vkDestroyPipeline(vk_core.device, g_rtx.pipeline, NULL);
|
||||||
|
|
|
@ -48,11 +48,18 @@ void initTextures( void )
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unloadSkybox( void );
|
||||||
|
|
||||||
void destroyTextures( void )
|
void destroyTextures( void )
|
||||||
{
|
{
|
||||||
for( unsigned int i = 0; i < vk_numTextures; i++ )
|
for( unsigned int i = 0; i < vk_numTextures; i++ )
|
||||||
VK_FreeTexture( 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( tglob.lightmapTextures, 0, sizeof( tglob.lightmapTextures ));
|
||||||
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
|
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
|
||||||
memset( vk_textures, 0, sizeof( vk_textures ));
|
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 )
|
static void VK_CreateInternalTextures( void )
|
||||||
{
|
{
|
||||||
int dx2, dy, d;
|
int dx2, dy, d;
|
||||||
|
@ -290,6 +299,22 @@ static void VK_CreateInternalTextures( void )
|
||||||
// cinematic dummy
|
// cinematic dummy
|
||||||
pic = Common_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR );
|
pic = Common_FakeImage( 640, 100, 1, IMAGE_HAS_COLOR );
|
||||||
tglob.cinTexture = VK_LoadTextureInternal( "*cintexture", pic, TF_NOMIPMAP|TF_CLAMP );
|
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)
|
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)
|
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);
|
||||||
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;
|
|
||||||
|
|
||||||
int mipCount = 0;
|
int mipCount = 0;
|
||||||
|
|
||||||
// TODO non-rbga textures
|
// TODO non-rbga textures
|
||||||
// TODO cubemaps
|
|
||||||
|
|
||||||
if (!pic->buffer)
|
for (int i = 0; i < num_layers; ++i) {
|
||||||
return false;
|
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;
|
if (i == 0)
|
||||||
tex->height = pic->height;
|
continue;
|
||||||
mipCount = CalcMipmapCount( tex, ( buf != NULL ));
|
|
||||||
|
|
||||||
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
|
// TODO this vvv
|
||||||
// // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
|
// // 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 )))
|
// if(( tex->depth == 1 ) && (( layers->width != tex->width ) || ( layers->height != tex->height )))
|
||||||
// data = GL_ResampleTexture( buf, pic->width, pic->height, tex->width, tex->height, normalMap );
|
// data = GL_ResampleTexture( buf, layers->width, layers->height, tex->width, tex->height, normalMap );
|
||||||
// else data = buf;
|
// 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 );
|
// data = GL_ApplyFilter( data, tex->width, tex->height );
|
||||||
|
|
||||||
// 1. Create VkImage w/ usage = DST|SAMPLED, layout=UNDEFINED
|
|
||||||
{
|
{
|
||||||
VkImageCreateInfo image_create_info = {
|
const xvk_image_create_t create = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.debug_name = tex->name,
|
||||||
.imageType = VK_IMAGE_TYPE_2D,
|
.width = tex->width,
|
||||||
.extent.width = pic->width,
|
.height = tex->height,
|
||||||
.extent.height = pic->height,
|
.mips = mipCount,
|
||||||
.extent.depth = 1,
|
.layers = num_layers,
|
||||||
.format = format,
|
.format = format,
|
||||||
.mipLevels = mipCount,
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
.arrayLayers = 1,
|
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
.tiling = tiling,
|
.has_alpha = layers[0]->flags & IMAGE_HAS_ALPHA,
|
||||||
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
.is_cubemap = cubemap,
|
||||||
.usage = usage,
|
|
||||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
||||||
};
|
};
|
||||||
XVK_CHECK(vkCreateImage(vk_core.device, &image_create_info, NULL, &tex->vk.image));
|
tex->vk.image = XVK_ImageCreate(&create);
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -517,7 +548,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
|
||||||
// 5.1.1 transitionToLayout(UNDEFINED -> DST)
|
// 5.1.1 transitionToLayout(UNDEFINED -> DST)
|
||||||
VkImageMemoryBarrier image_barrier = {
|
VkImageMemoryBarrier image_barrier = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.image = tex->vk.image,
|
.image = tex->vk.image.image,
|
||||||
.srcAccessMask = 0,
|
.srcAccessMask = 0,
|
||||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
@ -527,7 +558,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = mipCount,
|
.levelCount = mipCount,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = num_layers,
|
||||||
}};
|
}};
|
||||||
|
|
||||||
XVK_CHECK(vkBeginCommandBuffer(vk_core.cb_tex, &beginfo));
|
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);
|
0, 0, NULL, 0, NULL, 1, &image_barrier);
|
||||||
|
|
||||||
// 5.1.2 copyBufferToImage for all mip levels
|
// 5.1.2 copyBufferToImage for all mip levels
|
||||||
{
|
for (int layer = 0; layer < num_layers; ++layer) {
|
||||||
for (int mip = 0; mip < mipCount; ++mip)
|
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 width = Q_max( 1, ( pic->width >> mip ));
|
||||||
const int height = Q_max( 1, ( pic->height >> mip ));
|
const int height = Q_max( 1, ( pic->height >> mip ));
|
||||||
const size_t mip_size = CalcImageSize( pic->type, width, height, 1 );
|
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){
|
region.imageSubresource = (VkImageSubresourceLayers){
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
.mipLevel = mip,
|
.mipLevel = mip,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = layer,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
region.imageExtent = (VkExtent3D){
|
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
|
// 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;
|
staging_offset += mip_size;
|
||||||
}
|
}
|
||||||
|
@ -585,7 +617,7 @@ static qboolean VK_UploadTexture(vk_texture_t *tex, rgbdata_t *pic)
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = mipCount,
|
.levelCount = mipCount,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = num_layers,
|
||||||
};
|
};
|
||||||
vkCmdPipelineBarrier(vk_core.cb_tex,
|
vkCmdPipelineBarrier(vk_core.cb_tex,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
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));
|
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:
|
// TODO how should we approach this:
|
||||||
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
|
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
|
||||||
// - update descriptor sets in batch?
|
// - update descriptor sets in batch?
|
||||||
if (vk_desc.next_free != MAX_TEXTURES)
|
if (vk_desc.next_free != MAX_TEXTURES)
|
||||||
{
|
{
|
||||||
VkDescriptorImageInfo dii_tex = {
|
VkDescriptorImageInfo dii_tex = {
|
||||||
.imageView = tex->vk.image_view,
|
.imageView = tex->vk.image.view,
|
||||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
};
|
};
|
||||||
VkWriteDescriptorSet wds[] = { {
|
VkWriteDescriptorSet wds[] = { {
|
||||||
|
@ -707,7 +724,7 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
||||||
// upload texture
|
// upload texture
|
||||||
VK_ProcessImage( tex, pic );
|
VK_ProcessImage( tex, pic );
|
||||||
|
|
||||||
if( !VK_UploadTexture( tex, pic ))
|
if( !uploadTexture( tex, &pic, 1, false ))
|
||||||
{
|
{
|
||||||
memset( tex, 0, sizeof( vk_texture_t ));
|
memset( tex, 0, sizeof( vk_texture_t ));
|
||||||
gEngine.FS_FreeImage( pic ); // release source texture
|
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;
|
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 )
|
int VK_CreateTexture( const char *name, int width, int height, const void *buffer, texFlags_t flags )
|
||||||
{
|
{
|
||||||
gEngine.Con_Printf("VK FIXME: %s\n", __FUNCTION__);
|
gEngine.Con_Printf("VK FIXME: %s\n", __FUNCTION__);
|
||||||
|
@ -756,7 +786,7 @@ void VK_FreeTexture( unsigned int texnum ) {
|
||||||
ASSERT( tex != NULL );
|
ASSERT( tex != NULL );
|
||||||
|
|
||||||
// already freed?
|
// already freed?
|
||||||
if( !tex->vk.image ) return;
|
if( !tex->vk.image.image ) return;
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
if( !tex->name[0] )
|
if( !tex->name[0] )
|
||||||
|
@ -787,9 +817,7 @@ void VK_FreeTexture( unsigned int texnum ) {
|
||||||
gEngine.FS_FreeImage( tex->original );
|
gEngine.FS_FreeImage( tex->original );
|
||||||
*/
|
*/
|
||||||
|
|
||||||
vkDestroyImageView(vk_core.device, tex->vk.image_view, NULL);
|
XVK_ImageDestroy(&tex->vk.image);
|
||||||
vkDestroyImage(vk_core.device, tex->vk.image, NULL);
|
|
||||||
freeDeviceMemory(&tex->vk.device_memory);
|
|
||||||
memset(tex, 0, sizeof(*tex));
|
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 );
|
VK_ProcessImage( tex, pic );
|
||||||
|
|
||||||
if( !VK_UploadTexture( tex, pic ))
|
if( !uploadTexture( tex, &pic, 1, false ))
|
||||||
{
|
{
|
||||||
memset( tex, 0, sizeof( vk_texture_t ));
|
memset( tex, 0, sizeof( vk_texture_t ));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -834,51 +862,6 @@ int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags
|
||||||
return (tex - vk_textures);
|
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 XVK_TextureLookupF( const char *fmt, ...) {
|
||||||
int tex_id = 0;
|
int tex_id = 0;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
|
@ -892,25 +875,26 @@ int XVK_TextureLookupF( const char *fmt, ...) {
|
||||||
return tex_id;
|
return tex_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unloadSkybox( void )
|
static void unloadSkybox( void ) {
|
||||||
{
|
if (tglob.skybox_cube.vk.image.image) {
|
||||||
int i;
|
XVK_ImageDestroy(&tglob.skybox_cube.vk.image);
|
||||||
|
memset(&tglob.skybox_cube, 0, sizeof(tglob.skybox_cube));
|
||||||
// release old skybox
|
|
||||||
for( i = 0; i < 6; i++ )
|
|
||||||
{
|
|
||||||
if( !tglob.skyboxTextures[i] ) continue;
|
|
||||||
VK_FreeTexture( tglob.skyboxTextures[i] );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tglob.skyboxbasenum = 5800; // set skybox base (to let some mods load hi-res skyboxes)
|
|
||||||
|
|
||||||
memset( tglob.skyboxTextures, 0, sizeof( tglob.skyboxTextures ));
|
|
||||||
tglob.fCustomSkybox = false;
|
tglob.fCustomSkybox = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* r_skyBoxSuffix[6] = { "rt", "bk", "lf", "ft", "up", "dn" };
|
static struct {
|
||||||
//static const int r_skyTexOrder[6] = { 0, 2, 1, 3, 4, 5 };
|
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_MISSED 0
|
||||||
#define SKYBOX_HLSTYLE 1
|
#define SKYBOX_HLSTYLE 1
|
||||||
|
@ -929,7 +913,7 @@ static int CheckSkybox( const char *name )
|
||||||
for( j = 0; j < 6; j++ )
|
for( j = 0; j < 6; j++ )
|
||||||
{
|
{
|
||||||
// build side name
|
// 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 ))
|
if( gEngine.FS_FileExists( sidename, false ))
|
||||||
num_checked_sides++;
|
num_checked_sides++;
|
||||||
|
|
||||||
|
@ -941,7 +925,7 @@ static int CheckSkybox( const char *name )
|
||||||
for( j = 0; j < 6; j++ )
|
for( j = 0; j < 6; j++ )
|
||||||
{
|
{
|
||||||
// build side name
|
// 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 ))
|
if( gEngine.FS_FileExists( sidename, false ))
|
||||||
num_checked_sides++;
|
num_checked_sides++;
|
||||||
}
|
}
|
||||||
|
@ -958,6 +942,8 @@ void XVK_SetupSky( const char *skyboxname )
|
||||||
char loadname[MAX_STRING];
|
char loadname[MAX_STRING];
|
||||||
char sidename[MAX_STRING];
|
char sidename[MAX_STRING];
|
||||||
int i, result, len;
|
int i, result, len;
|
||||||
|
rgbdata_t *sides[6];
|
||||||
|
qboolean success = false;
|
||||||
|
|
||||||
if( !COM_CheckString( skyboxname ))
|
if( !COM_CheckString( skyboxname ))
|
||||||
{
|
{
|
||||||
|
@ -990,21 +976,43 @@ void XVK_SetupSky( const char *skyboxname )
|
||||||
for( i = 0; i < 6; i++ )
|
for( i = 0; i < 6; i++ )
|
||||||
{
|
{
|
||||||
if( result == SKYBOX_HLSTYLE )
|
if( result == SKYBOX_HLSTYLE )
|
||||||
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, r_skyBoxSuffix[i] );
|
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 );
|
sides[i] = gEngine.FS_LoadImage( sidename, NULL, 0);
|
||||||
if( !tglob.skyboxTextures[i] ) break;
|
if (!sides[i] || !sides[i]->buffer)
|
||||||
gEngine.Con_DPrintf( "%s%s%s", skyboxname, r_skyBoxSuffix[i], i != 5 ? ", " : ". " );
|
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;
|
tglob.fCustomSkybox = true;
|
||||||
gEngine.Con_DPrintf( "done\n" );
|
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
|
#pragma once
|
||||||
#include "vk_core.h"
|
#include "vk_core.h"
|
||||||
|
#include "vk_image.h"
|
||||||
|
|
||||||
#include "xash3d_types.h"
|
#include "xash3d_types.h"
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
@ -14,9 +15,7 @@ typedef struct vk_texture_s
|
||||||
uint texnum;
|
uint texnum;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
VkImage image;
|
xvk_image_t image;
|
||||||
VkImageView image_view;
|
|
||||||
device_memory_t device_memory;
|
|
||||||
VkDescriptorSet descriptor;
|
VkDescriptorSet descriptor;
|
||||||
} vk;
|
} vk;
|
||||||
|
|
||||||
|
@ -37,13 +36,15 @@ typedef struct vk_textures_global_s
|
||||||
int alphaskyTexture; // quake1 alpha-sky layer
|
int alphaskyTexture; // quake1 alpha-sky layer
|
||||||
int lightmapTextures[MAX_LIGHTMAPS];
|
int lightmapTextures[MAX_LIGHTMAPS];
|
||||||
int dlightTexture; // custom dlight texture
|
int dlightTexture; // custom dlight texture
|
||||||
int skyboxTextures[6]; // skybox sides
|
|
||||||
int cinTexture; // cinematic texture
|
int cinTexture; // cinematic texture
|
||||||
|
|
||||||
int skytexturenum; // this not a gl_texturenum!
|
int skytexturenum; // this not a gl_texturenum!
|
||||||
int skyboxbasenum; // start with 5800 FIXME remove this, lewa says this is a GL1 hack
|
int skyboxbasenum; // start with 5800 FIXME remove this, lewa says this is a GL1 hack
|
||||||
|
|
||||||
qboolean fCustomSkybox; // TODO do we need this for anything?
|
qboolean fCustomSkybox; // TODO do we need this for anything?
|
||||||
|
|
||||||
|
vk_texture_t skybox_cube;
|
||||||
|
vk_texture_t cubemap_placeholder;
|
||||||
} vk_textures_global_t;
|
} vk_textures_global_t;
|
||||||
|
|
||||||
// TODO rename this consistently
|
// 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 );
|
void VK_FreeTexture( unsigned int texnum );
|
||||||
int VK_LoadTextureFromBuffer( const char *name, rgbdata_t *pic, texFlags_t flags, qboolean update );
|
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, ...);
|
int XVK_TextureLookupF( const char *fmt, ...);
|
||||||
|
|
||||||
#define VK_LoadTextureInternal( name, pic, flags ) VK_LoadTextureFromBuffer( name, pic, flags, false )
|
#define VK_LoadTextureInternal( name, pic, flags ) VK_LoadTextureFromBuffer( name, pic, flags, false )
|
||||||
|
|
||||||
void XVK_SetupSky( const char *skyboxname );
|
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