Merge pull request #593 from w23/materials-table
Materials table and friends - [ ] KTX2 #154 - [x] proof of concept - [x] proper alignment for blocks (validation complains) - [ ] texture leaks: #594 - [x] investigate - [x] `inherit`/`use` - [x] Fix #211 - [x] make materials table - [ ] ~~make materials by-name lookup independent of texture table, stop doing dummy textures~~ moved to #601 - [ ] normalmap glitches, #595 - [x] investigated, seems to be offline normalization vs bit depth/precision issue; needs offline changes
This commit is contained in:
commit
726fcee3f7
|
@ -600,3 +600,38 @@ For multiple replacements:
|
||||||
"_xvk_texture_material" "generic028 generic_metal1 generic029 generic_metal2 ... ..."
|
"_xvk_texture_material" "generic028 generic_metal1 generic029 generic_metal2 ... ..."
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# 2023-10-02 E305
|
||||||
|
## Materials table
|
||||||
|
|
||||||
|
### Operations
|
||||||
|
- Clean
|
||||||
|
- load materials from file
|
||||||
|
- current format (mixes materials and selection rules a bit)
|
||||||
|
- other formats (can only support named materials w/o any selection rules)
|
||||||
|
- inherit/use from previously defined materials
|
||||||
|
- needs index/value by name below
|
||||||
|
- Get materials by:
|
||||||
|
- value by tex_id
|
||||||
|
- value by tex_id + rendermode
|
||||||
|
- value by tex_id + chrome
|
||||||
|
- ~~(do we need to specialize "for_chrome"? were there any cases where it would be useful?)~~ It seems not.
|
||||||
|
- index by name (currently works by having a dummy texture with this name; reuses vk_textures hash search)
|
||||||
|
- Lazy: Getting by value performs loading, getting by index does not.
|
||||||
|
|
||||||
|
### Data structures overview
|
||||||
|
- materials[mat_id] -- indexed by indexes independent of tex_id, referenced externally, requires stable index.
|
||||||
|
- (typical material fields)
|
||||||
|
- possibly lazily loaded
|
||||||
|
- arg `-vknolazymaterials` for development. To immediately recognize missing textues, not until they are requested for the first time.
|
||||||
|
- fallback onto default/error texture on lazy loading errors
|
||||||
|
- tex_to_material[tex_id] table (hash table, array, whatever)
|
||||||
|
- state -- {NotChecked, NoReplacement, ReplacementExists}
|
||||||
|
- NotChecked -- means there was no explicit replacement, but we still can check for auto replacement (TEXNAME_roughness.png, etc)
|
||||||
|
- NoReplacement -- there's nothing to replace with, use original texture with default material parameters.
|
||||||
|
- mat_id -- index into materials[] table if there's a replacement
|
||||||
|
- rendermodes-specific overrides (fixed array? too expensive; linked list?)
|
||||||
|
- rendermode
|
||||||
|
- mat_id
|
||||||
|
- name_to_material[] -- string "name" to mat_id
|
||||||
|
- hash table of some sorts
|
||||||
|
|
|
@ -21,9 +21,10 @@
|
||||||
enum {
|
enum {
|
||||||
SPEEDS_BIT_OFF = 0, // `r_speeds 0` turns off all performance stats display
|
SPEEDS_BIT_OFF = 0, // `r_speeds 0` turns off all performance stats display
|
||||||
SPEEDS_BIT_SIMPLE = 1, // `r_speeds 1` displays only basic info about frame time
|
SPEEDS_BIT_SIMPLE = 1, // `r_speeds 1` displays only basic info about frame time
|
||||||
SPEEDS_BIT_STATS = 2, // `r_speeds 2` displays additional metrics, i.e. lights counts, dynamic geometry upload sizes, etc (TODO)
|
SPEEDS_BIT_STATS = 2, // `r_speeds 2` displays additional metrics, i.e. lights counts, dynamic geometry upload sizes, etc
|
||||||
SPEEDS_BIT_GPU_USAGE = 4, // `r_speeds 4` displays overall GPU usage stats (TODO)
|
SPEEDS_BIT_GRAPHS = 4, // `r_speeds 4` display instrumental metrics graphs, controlled by r_speeds_graphs var
|
||||||
SPEEDS_BIT_FRAME = 8, // `r_speeds 8` diplays details instrumental profiler frame data, e.g. specific functions times graphs, etc
|
SPEEDS_BIT_FRAME = 8, // `r_speeds 8` diplays details instrumental profiler flame graph
|
||||||
|
// TODO SPEEDS_BIT_GPU_USAGE = 16, // `r_speeds 16` displays overall GPU usage stats
|
||||||
|
|
||||||
// These bits can be combined, e.g. `r_speeds 9`, 8+1, will display 1: basic timing info and 8: frame graphs
|
// These bits can be combined, e.g. `r_speeds 9`, 8+1, will display 1: basic timing info and 8: frame graphs
|
||||||
};
|
};
|
||||||
|
@ -972,10 +973,11 @@ void R_SpeedsDisplayMore(uint32_t prev_frame_index, const struct vk_combuf_scope
|
||||||
|
|
||||||
{
|
{
|
||||||
int y = 100;
|
int y = 100;
|
||||||
const int draw = speeds_bits & SPEEDS_BIT_FRAME;
|
const int draw_frame = speeds_bits & SPEEDS_BIT_FRAME;
|
||||||
y = drawFrames( draw, prev_frame_index, y, gpurofl, gpurofl_count );
|
y = drawFrames( draw_frame, prev_frame_index, y, gpurofl, gpurofl_count );
|
||||||
|
|
||||||
if (draw)
|
const int draw_graphs = speeds_bits & SPEEDS_BIT_GRAPHS;
|
||||||
|
if (draw_graphs)
|
||||||
y = drawGraphs(y + 10);
|
y = drawGraphs(y + 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,13 +88,14 @@ bool getHit(vec3 origin, vec3 direction, inout RayPayloadPrimary payload) {
|
||||||
//L = rayQueryGetIntersectionTEXT(rq, true);
|
//L = rayQueryGetIntersectionTEXT(rq, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
const int INDIRECT_SCALE = 2;
|
||||||
|
|
||||||
void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specular) {
|
void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specular) {
|
||||||
diffuse = vec3(0.);
|
diffuse = vec3(0.);
|
||||||
specular = vec3(0.);
|
specular = vec3(0.);
|
||||||
|
|
||||||
const vec4 material_data = imageLoad(material_rmxx, pix);
|
const vec4 material_data = imageLoad(material_rmxx, pix);
|
||||||
const vec4 base_a = imageLoad(base_color_a, pix);
|
const vec4 base_a = SRGBtoLINEAR(imageLoad(base_color_a, pix));
|
||||||
|
|
||||||
MaterialProperties material;
|
MaterialProperties material;
|
||||||
material.baseColor = vec3(1.f);
|
material.baseColor = vec3(1.f);
|
||||||
|
@ -180,7 +181,6 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int INDIRECT_SCALE = 2;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
const ivec2 pix = ivec2(gl_GlobalInvocationID);
|
const ivec2 pix = ivec2(gl_GlobalInvocationID);
|
||||||
|
|
|
@ -30,6 +30,7 @@ const float dlight_attenuation_const = 5000.;
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(0.);
|
outColor = vec4(0.);
|
||||||
const vec4 tex_color = texture(sTexture0, vTexture0);
|
const vec4 tex_color = texture(sTexture0, vTexture0);
|
||||||
|
|
||||||
// TODO make sure textures are premultiplied alpha
|
// TODO make sure textures are premultiplied alpha
|
||||||
const vec4 baseColor = vColor * tex_color;
|
const vec4 baseColor = vColor * tex_color;
|
||||||
|
|
||||||
|
@ -48,6 +49,4 @@ void main() {
|
||||||
const float attenuation = dlight_attenuation_const / (d2 + r2 * .5);
|
const float attenuation = dlight_attenuation_const / (d2 + r2 * .5);
|
||||||
outColor.rgb += baseColor.rgb * light_color * max(0., dot(normalize(light_dir), vNormal)) * attenuation;
|
outColor.rgb += baseColor.rgb * light_color * max(0., dot(normalize(light_dir), vNormal)) * attenuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
//outColor.rgb = vNormal * .5 + .5;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define SRGB_FAST_APPROXIMATION
|
#ifndef RT_COLOR_SPACES_GLSL_INCLUDED
|
||||||
|
#define RT_COLOR_SPACES_GLSL_INCLUDED
|
||||||
#ifdef SRGB_FAST_APPROXIMATION
|
#ifdef SRGB_FAST_APPROXIMATION
|
||||||
#define LINEARtoSRGB OECF_sRGBFast
|
#define LINEARtoSRGB OECF_sRGBFast
|
||||||
#define SRGBtoLINEAR sRGB_OECFFast
|
#define SRGBtoLINEAR sRGB_OECFFast
|
||||||
|
@ -63,3 +63,5 @@ vec3 OECF_sRGBFast(const vec3 linear) {
|
||||||
vec4 OECF_sRGBFast(const vec4 linear) {
|
vec4 OECF_sRGBFast(const vec4 linear) {
|
||||||
return vec4(pow(linear.rgb, vec3(1.0 / 2.2)), linear.w);
|
return vec4(pow(linear.rgb, vec3(1.0 / 2.2)), linear.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif //ifndef RT_COLOR_SPACES_GLSL_INCLUDED
|
||||||
|
|
|
@ -41,10 +41,14 @@ layout(set = 0, binding = 18) uniform sampler2D textures[MAX_TEXTURES];
|
||||||
include "bluenoise.glsl"
|
include "bluenoise.glsl"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//layout(set = 0, binding = 19) uniform sampler2D textures[MAX_TEXTURES];
|
||||||
|
|
||||||
|
|
||||||
const int INDIRECT_SCALE = 2;
|
const int INDIRECT_SCALE = 2;
|
||||||
|
|
||||||
//#define DEBUG_TEXTURE normals_gs
|
//#define DEBUG_TEXTURE normals_gs
|
||||||
//#define DEBUG_TEXTURE emissive
|
//#define DEBUG_TEXTURE emissive
|
||||||
|
//#define DEBUG_TEXTURE base_color_a
|
||||||
//#define DEBUG_TEXTURE light_point_diffuse
|
//#define DEBUG_TEXTURE light_point_diffuse
|
||||||
//#define DEBUG_NORMAL
|
//#define DEBUG_NORMAL
|
||||||
//layout(set = 0, binding = 18, rgba8) uniform readonly image2D material_rmxx;
|
//layout(set = 0, binding = 18, rgba8) uniform readonly image2D material_rmxx;
|
||||||
|
@ -202,9 +206,31 @@ void main() {
|
||||||
/* } */
|
/* } */
|
||||||
|
|
||||||
#if defined(DEBUG_TEXTURE)
|
#if defined(DEBUG_TEXTURE)
|
||||||
|
//if (pix.x < res.x / 2) {
|
||||||
|
//imageStore(out_dest, pix, vec4(LINEARtoSRGB(texture(textures[161], vec2(pix)/vec2(res)).rgb), 0.)); return;
|
||||||
|
//}
|
||||||
imageStore(out_dest, pix, vec4(LINEARtoSRGB(imageLoad(DEBUG_TEXTURE, pix).rgb), 0.)); return;
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(imageLoad(DEBUG_TEXTURE, pix).rgb), 0.)); return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (pix.x < res.x / 4) {
|
||||||
|
imageStore(out_dest, pix, vec4(imageLoad(base_color_a, pix).rgb, 0.)); return;
|
||||||
|
} else if (pix.x < res.x / 2) {
|
||||||
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(imageLoad(emissive, pix).rgb), 0.)); return;
|
||||||
|
} else if (pix.x < res.x * 3 / 4) {
|
||||||
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(fract(
|
||||||
|
imageLoad(light_poly_diffuse, pix).rgb
|
||||||
|
+ imageLoad(light_poly_specular, pix).rgb
|
||||||
|
+ imageLoad(light_point_diffuse, pix).rgb
|
||||||
|
+ imageLoad(light_point_specular, pix).rgb
|
||||||
|
)), 0.)); return;
|
||||||
|
} else {
|
||||||
|
imageStore(out_dest, pix, vec4(LINEARtoSRGB(
|
||||||
|
imageLoad(indirect_diffuse, pix / INDIRECT_SCALE).rgb
|
||||||
|
+ imageLoad(indirect_specular, pix / INDIRECT_SCALE).rgb
|
||||||
|
), 0.)); return;
|
||||||
|
}*/
|
||||||
|
|
||||||
//imageStore(out_dest, pix, vec4(fract(imageLoad(position_t, pix).rgb/10.), 0.)); return;
|
//imageStore(out_dest, pix, vec4(fract(imageLoad(position_t, pix).rgb/10.), 0.)); return;
|
||||||
//imageStore(out_dest, pix, vec4(fract(imageLoad(geometry_prev_position, pix).rgb/50.), 0.)); return;
|
//imageStore(out_dest, pix, vec4(fract(imageLoad(geometry_prev_position, pix).rgb/50.), 0.)); return;
|
||||||
|
|
||||||
|
@ -278,8 +304,8 @@ void main() {
|
||||||
//imageStore(out_dest, pix, vec4(LINEARtoSRGB(diffuse), 0.)); return;
|
//imageStore(out_dest, pix, vec4(LINEARtoSRGB(diffuse), 0.)); return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vec4 base_color_a = imageLoad(base_color_a, pix);
|
const vec4 base_color_a = SRGBtoLINEAR(imageLoad(base_color_a, pix));
|
||||||
colour *= SRGBtoLINEAR(base_color_a.rgb);
|
colour *= base_color_a.rgb;
|
||||||
colour += imageLoad(emissive, pix).rgb;
|
colour += imageLoad(emissive, pix).rgb;
|
||||||
colour = LINEARtoSRGB(colour);
|
colour = LINEARtoSRGB(colour);
|
||||||
|
|
||||||
|
|
|
@ -107,13 +107,13 @@ void main() {
|
||||||
L = rayQueryGetIntersectionTEXT(rq, true);
|
L = rayQueryGetIntersectionTEXT(rq, true);
|
||||||
} else {
|
} else {
|
||||||
// Draw skybox when nothing is hit
|
// Draw skybox when nothing is hit
|
||||||
payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, ray.direction).rgb);
|
payload.emissive.rgb = texture(skybox, ray.direction).rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
traceSimpleBlending(ray.origin, ray.direction, L, payload.emissive.rgb, payload.base_color_a.rgb);
|
traceSimpleBlending(ray.origin, ray.direction, L, payload.emissive.rgb, payload.base_color_a.rgb);
|
||||||
|
|
||||||
imageStore(out_position_t, pix, payload.hit_t);
|
imageStore(out_position_t, pix, payload.hit_t);
|
||||||
imageStore(out_base_color_a, pix, payload.base_color_a);
|
imageStore(out_base_color_a, pix, LINEARtoSRGB(payload.base_color_a));
|
||||||
imageStore(out_normals_gs, pix, payload.normals_gs);
|
imageStore(out_normals_gs, pix, payload.normals_gs);
|
||||||
//imageStore(out_material_rmxx, pix, vec4(payload.material_rmxx.rg, 0, uintToFloat01(xxhash32(debug_geometry_index))));
|
//imageStore(out_material_rmxx, pix, vec4(payload.material_rmxx.rg, 0, uintToFloat01(xxhash32(debug_geometry_index))));
|
||||||
imageStore(out_material_rmxx, pix, payload.material_rmxx);
|
imageStore(out_material_rmxx, pix, payload.material_rmxx);
|
||||||
|
|
|
@ -30,7 +30,7 @@ void main() {
|
||||||
const Kusok kusok = getKusok(geom.kusok_index);
|
const Kusok kusok = getKusok(geom.kusok_index);
|
||||||
|
|
||||||
if (kusok.material.tex_base_color == TEX_BASE_SKYBOX) {
|
if (kusok.material.tex_base_color == TEX_BASE_SKYBOX) {
|
||||||
payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, gl_WorldRayDirectionEXT).rgb);
|
payload.emissive.rgb = texture(skybox, gl_WorldRayDirectionEXT).rgb;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const vec4 color = getModelHeader(gl_InstanceID).color * kusok.material.base_color;
|
const vec4 color = getModelHeader(gl_InstanceID).color * kusok.material.base_color;
|
||||||
|
@ -55,7 +55,7 @@ void main() {
|
||||||
#if 1
|
#if 1
|
||||||
// Real correct emissive color
|
// Real correct emissive color
|
||||||
//payload.emissive.rgb = kusok.emissive;
|
//payload.emissive.rgb = kusok.emissive;
|
||||||
payload.emissive.rgb = clamp(kusok.emissive / (1.0/3.0) / 25, 0, 1.5) * SRGBtoLINEAR(payload.base_color_a.rgb);
|
payload.emissive.rgb = clamp(kusok.emissive / (1.0/3.0) / 25, 0, 1.5) * payload.base_color_a.rgb;
|
||||||
#else
|
#else
|
||||||
// Fake texture color
|
// Fake texture color
|
||||||
if (any(greaterThan(kusok.emissive, vec3(0.))))
|
if (any(greaterThan(kusok.emissive, vec3(0.))))
|
||||||
|
|
|
@ -31,7 +31,7 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
|
||||||
const Material material = kusok.material;
|
const Material material = kusok.material;
|
||||||
|
|
||||||
if (kusok.material.tex_base_color == TEX_BASE_SKYBOX) {
|
if (kusok.material.tex_base_color == TEX_BASE_SKYBOX) {
|
||||||
payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, rayDirection).rgb);
|
payload.emissive.rgb = texture(skybox, rayDirection).rgb;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
payload.base_color_a = sampleTexture(material.tex_base_color, geom.uv, geom.uv_lods);
|
payload.base_color_a = sampleTexture(material.tex_base_color, geom.uv, geom.uv_lods);
|
||||||
|
@ -45,9 +45,36 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
|
||||||
T = normalize(T - dot(T, geom.normal_shading) * geom.normal_shading);
|
T = normalize(T - dot(T, geom.normal_shading) * geom.normal_shading);
|
||||||
const vec3 B = normalize(cross(geom.normal_shading, T));
|
const vec3 B = normalize(cross(geom.normal_shading, T));
|
||||||
const mat3 TBN = mat3(T, B, geom.normal_shading);
|
const mat3 TBN = mat3(T, B, geom.normal_shading);
|
||||||
vec3 tnorm = sampleTexture(tex_normal, geom.uv, geom.uv_lods).xyz * 2. - 1.; // TODO is this sampling correct for normal data?
|
|
||||||
|
// Get to KTX2 normal maps eventually
|
||||||
|
//#define KTX2
|
||||||
|
#ifdef KTX2
|
||||||
|
// We expect KTX2 normalmaps to have only 2 SNORM components.
|
||||||
|
// TODO: BC6H only can do signed or unsigned 16-bit floats. It can't normalize them on its own. So we either deal with
|
||||||
|
// sub-par 10bit precision for <1 values. Or do normalization manually in shader. Manual normalization implies prepa-
|
||||||
|
// ring normalmaps in a special way, i.e. scaling vector components to full f16 scale.
|
||||||
|
#define NORMALMAP_SNORM
|
||||||
|
#define NORMALMAP_2COMP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NORMALMAP_SNORM // [-1..1]
|
||||||
|
// TODO is this sampling correct for normal data?
|
||||||
|
vec3 tnorm = sampleTexture(tex_normal, geom.uv, geom.uv_lods).xyz;
|
||||||
|
#else // Older UNORM [0..1]
|
||||||
|
vec3 tnorm = sampleTexture(tex_normal, geom.uv, geom.uv_lods).xyz * 2. - 1.;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef NORMALMAP_2COMP
|
||||||
|
// Older 8-bit PNG suffers from quantization.
|
||||||
|
// Smoothen quantization by normalizing it
|
||||||
|
tnorm = normalize(tnorm);
|
||||||
|
#endif
|
||||||
|
|
||||||
tnorm.xy *= material.normal_scale;
|
tnorm.xy *= material.normal_scale;
|
||||||
|
|
||||||
|
// Restore z based on scaled xy
|
||||||
tnorm.z = sqrt(max(0., 1. - dot(tnorm.xy, tnorm.xy)));
|
tnorm.z = sqrt(max(0., 1. - dot(tnorm.xy, tnorm.xy)));
|
||||||
|
|
||||||
geom.normal_shading = normalize(TBN * tnorm);
|
geom.normal_shading = normalize(TBN * tnorm);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,7 +89,8 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
|
||||||
//payload.emissive.rgb = kusok.emissive * SRGBtoLINEAR(payload.base_color_a.rgb);
|
//payload.emissive.rgb = kusok.emissive * SRGBtoLINEAR(payload.base_color_a.rgb);
|
||||||
//payload.emissive.rgb = clamp((kusok.emissive * (1.0/3.0) / 20), 0, 1.0) * SRGBtoLINEAR(payload.base_color_a.rgb);
|
//payload.emissive.rgb = clamp((kusok.emissive * (1.0/3.0) / 20), 0, 1.0) * SRGBtoLINEAR(payload.base_color_a.rgb);
|
||||||
//payload.emissive.rgb = (sqrt(sqrt(kusok.emissive)) * (1.0/3.0)) * SRGBtoLINEAR(payload.base_color_a.rgb);
|
//payload.emissive.rgb = (sqrt(sqrt(kusok.emissive)) * (1.0/3.0)) * SRGBtoLINEAR(payload.base_color_a.rgb);
|
||||||
payload.emissive.rgb = (sqrt(kusok.emissive) / 8) * SRGBtoLINEAR(payload.base_color_a.rgb);
|
payload.emissive.rgb = (sqrt(kusok.emissive) / 8) * payload.base_color_a.rgb;
|
||||||
|
//payload.emissive.rgb = kusok.emissive * payload.base_color_a.rgb;
|
||||||
#else
|
#else
|
||||||
// Fake texture color
|
// Fake texture color
|
||||||
if (any(greaterThan(kusok.emissive, vec3(0.))))
|
if (any(greaterThan(kusok.emissive, vec3(0.))))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef RT_GEOMETRY_GLSL_INCLUDED
|
#ifndef RT_GEOMETRY_GLSL_INCLUDED
|
||||||
#define RT_GEOMETRY_GLSL_INCLUDED
|
#define RT_GEOMETRY_GLSL_INCLUDED
|
||||||
#include "utils.glsl"
|
#include "utils.glsl"
|
||||||
|
#include "color_spaces.glsl"
|
||||||
|
|
||||||
// Taken from Journal of Computer Graphics Techniques, Vol. 10, No. 1, 2021.
|
// Taken from Journal of Computer Graphics Techniques, Vol. 10, No. 1, 2021.
|
||||||
// Improved Shader and Texture Level of Detail Using Ray Cones,
|
// Improved Shader and Texture Level of Detail Using Ray Cones,
|
||||||
|
@ -156,9 +157,9 @@ MiniGeometry readCandidateMiniGeometry(rayQueryEXT rq) {
|
||||||
const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary);
|
const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary);
|
||||||
|
|
||||||
const vec4 colors[3] = {
|
const vec4 colors[3] = {
|
||||||
unpackUnorm4x8(GET_VERTEX(vi1).color),
|
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi1).color)),
|
||||||
unpackUnorm4x8(GET_VERTEX(vi2).color),
|
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi2).color)),
|
||||||
unpackUnorm4x8(GET_VERTEX(vi3).color),
|
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi3).color)),
|
||||||
};
|
};
|
||||||
|
|
||||||
MiniGeometry ret;
|
MiniGeometry ret;
|
||||||
|
|
|
@ -53,7 +53,7 @@ void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout
|
||||||
const vec4 texture_color = texture(textures[nonuniformEXT(kusok.material.tex_base_color)], geom.uv);
|
const vec4 texture_color = texture(textures[nonuniformEXT(kusok.material.tex_base_color)], geom.uv);
|
||||||
const vec4 mm_color = model.color * kusok.material.base_color;
|
const vec4 mm_color = model.color * kusok.material.base_color;
|
||||||
float alpha = mm_color.a * texture_color.a * geom.vertex_color.a;
|
float alpha = mm_color.a * texture_color.a * geom.vertex_color.a;
|
||||||
vec3 color = mm_color.rgb * SRGBtoLINEAR(texture_color.rgb) * geom.vertex_color.rgb * alpha;
|
vec3 color = mm_color.rgb * texture_color.rgb * geom.vertex_color.rgb * alpha;
|
||||||
|
|
||||||
if (model.mode == MATERIAL_MODE_BLEND_GLOW) {
|
if (model.mode == MATERIAL_MODE_BLEND_GLOW) {
|
||||||
// Glow is additive + small overshoot
|
// Glow is additive + small overshoot
|
||||||
|
|
|
@ -1088,6 +1088,8 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int tex_id = orig_tex_id;
|
int tex_id = orig_tex_id;
|
||||||
|
|
||||||
|
// TODO this patching should probably override entity patching below
|
||||||
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
|
const xvk_patch_surface_t *const psurf = R_VkPatchGetSurface(surface_index);
|
||||||
if (psurf && psurf->tex_id >= 0)
|
if (psurf && psurf->tex_id >= 0)
|
||||||
tex_id = psurf->tex_id;
|
tex_id = psurf->tex_id;
|
||||||
|
@ -1121,7 +1123,7 @@ static qboolean fillBrushSurfaces(fill_geometries_args_t args) {
|
||||||
qboolean material_assigned = false;
|
qboolean material_assigned = false;
|
||||||
if (entity_patch) {
|
if (entity_patch) {
|
||||||
for (int i = 0; i < entity_patch->matmap_count; ++i) {
|
for (int i = 0; i < entity_patch->matmap_count; ++i) {
|
||||||
if (entity_patch->matmap[i].from_tex == tex_id) {
|
if (entity_patch->matmap[i].from_tex == orig_tex_id) {
|
||||||
model_geometry->material = R_VkMaterialGetForTexture(entity_patch->matmap[i].to_mat.index);
|
model_geometry->material = R_VkMaterialGetForTexture(entity_patch->matmap[i].to_mat.index);
|
||||||
material_assigned = true;
|
material_assigned = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -12,7 +12,8 @@ typedef struct descriptor_pool_s
|
||||||
int next_free;
|
int next_free;
|
||||||
//uint32_t *free_set;
|
//uint32_t *free_set;
|
||||||
|
|
||||||
VkDescriptorSet sets[MAX_TEXTURES];
|
// * 2 because of unorm views for trad renderer
|
||||||
|
VkDescriptorSet sets[MAX_TEXTURES * 2];
|
||||||
VkDescriptorSetLayout one_texture_layout;
|
VkDescriptorSetLayout one_texture_layout;
|
||||||
|
|
||||||
// FIXME HOW THE F
|
// FIXME HOW THE F
|
||||||
|
@ -31,7 +32,7 @@ typedef union {
|
||||||
VkDescriptorImageInfo image;
|
VkDescriptorImageInfo image;
|
||||||
VkDescriptorImageInfo *image_array;
|
VkDescriptorImageInfo *image_array;
|
||||||
VkWriteDescriptorSetAccelerationStructureKHR accel;
|
VkWriteDescriptorSetAccelerationStructureKHR accel;
|
||||||
const struct xvk_image_s *image_object;
|
const struct r_vk_image_s *image_object;
|
||||||
} vk_descriptor_value_t;
|
} vk_descriptor_value_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -259,6 +259,7 @@ void VK_RenderFrame( const struct ref_viewpass_s *rvp )
|
||||||
}
|
}
|
||||||
|
|
||||||
static void enqueueRendering( vk_combuf_t* combuf, qboolean draw ) {
|
static void enqueueRendering( vk_combuf_t* combuf, qboolean draw ) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(enqueue, __FUNCTION__);
|
||||||
const VkClearValue clear_value[] = {
|
const VkClearValue clear_value[] = {
|
||||||
{.color = {{1., 0., 0., 0.}}},
|
{.color = {{1., 0., 0., 0.}}},
|
||||||
{.depthStencil = {1., 0.}} // TODO reverse-z
|
{.depthStencil = {1., 0.}} // TODO reverse-z
|
||||||
|
@ -307,10 +308,12 @@ static void enqueueRendering( vk_combuf_t* combuf, qboolean draw ) {
|
||||||
vkCmdEndRenderPass(cmdbuf);
|
vkCmdEndRenderPass(cmdbuf);
|
||||||
|
|
||||||
g_frame.current.phase = Phase_RenderingEnqueued;
|
g_frame.current.phase = Phase_RenderingEnqueued;
|
||||||
|
APROF_SCOPE_END(enqueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME pass frame, not combuf (possible desync)
|
// FIXME pass frame, not combuf (possible desync)
|
||||||
static void submit( vk_combuf_t* combuf, qboolean wait, qboolean draw ) {
|
static void submit( vk_combuf_t* combuf, qboolean wait, qboolean draw ) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(submit, __FUNCTION__);
|
||||||
ASSERT(g_frame.current.phase == Phase_RenderingEnqueued);
|
ASSERT(g_frame.current.phase == Phase_RenderingEnqueued);
|
||||||
|
|
||||||
const VkCommandBuffer cmdbuf = combuf->cmdbuf;
|
const VkCommandBuffer cmdbuf = combuf->cmdbuf;
|
||||||
|
@ -390,6 +393,8 @@ static void submit( vk_combuf_t* combuf, qboolean wait, qboolean draw ) {
|
||||||
/* } */
|
/* } */
|
||||||
g_frame.current.phase = Phase_Idle;
|
g_frame.current.phase = Phase_Idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APROF_SCOPE_END(submit);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static VkCommandBuffer currentCommandBuffer( void ) {
|
inline static VkCommandBuffer currentCommandBuffer( void ) {
|
||||||
|
@ -510,7 +515,7 @@ static qboolean canBlitFromSwapchainToFormat( VkFormat dest_format ) {
|
||||||
|
|
||||||
static rgbdata_t *XVK_ReadPixels( void ) {
|
static rgbdata_t *XVK_ReadPixels( void ) {
|
||||||
const VkFormat dest_format = VK_FORMAT_R8G8B8A8_UNORM;
|
const VkFormat dest_format = VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
xvk_image_t dest_image;
|
r_vk_image_t dest_image;
|
||||||
const VkImage frame_image = g_frame.current.framebuffer.image;
|
const VkImage frame_image = g_frame.current.framebuffer.image;
|
||||||
rgbdata_t *r_shot = NULL;
|
rgbdata_t *r_shot = NULL;
|
||||||
qboolean blit = canBlitFromSwapchainToFormat( dest_format );
|
qboolean blit = canBlitFromSwapchainToFormat( dest_format );
|
||||||
|
@ -525,7 +530,7 @@ static rgbdata_t *XVK_ReadPixels( void ) {
|
||||||
|
|
||||||
// Create destination image to blit/copy framebuffer pixels to
|
// Create destination image to blit/copy framebuffer pixels to
|
||||||
{
|
{
|
||||||
const xvk_image_create_t xic = {
|
const r_vk_image_create_t xic = {
|
||||||
.debug_name = "screenshot",
|
.debug_name = "screenshot",
|
||||||
.width = vk_frame.width,
|
.width = vk_frame.width,
|
||||||
.height = vk_frame.height,
|
.height = vk_frame.height,
|
||||||
|
@ -534,11 +539,10 @@ static rgbdata_t *XVK_ReadPixels( void ) {
|
||||||
.format = dest_format,
|
.format = dest_format,
|
||||||
.tiling = VK_IMAGE_TILING_LINEAR,
|
.tiling = VK_IMAGE_TILING_LINEAR,
|
||||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
.has_alpha = false,
|
.flags = 0,
|
||||||
.is_cubemap = false,
|
|
||||||
.memory_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
.memory_props = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
|
||||||
};
|
};
|
||||||
dest_image = XVK_ImageCreate(&xic);
|
dest_image = R_VkImageCreate(&xic);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that all rendering ops are enqueued
|
// Make sure that all rendering ops are enqueued
|
||||||
|
@ -700,7 +704,7 @@ static rgbdata_t *XVK_ReadPixels( void ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XVK_ImageDestroy( &dest_image );
|
R_VkImageDestroy( &dest_image );
|
||||||
|
|
||||||
return r_shot;
|
return r_shot;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "vk_image.h"
|
#include "vk_image.h"
|
||||||
|
#include "vk_logs.h"
|
||||||
|
|
||||||
static const VkImageUsageFlags usage_bits_implying_views =
|
static const VkImageUsageFlags usage_bits_implying_views =
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||||
|
@ -16,11 +17,92 @@ static const VkImageUsageFlags usage_bits_implying_views =
|
||||||
VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR;
|
VK_IMAGE_USAGE_VIDEO_ENCODE_DPB_BIT_KHR;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
static VkFormat unormFormatFor(VkFormat fmt) {
|
||||||
|
switch (fmt) {
|
||||||
|
case VK_FORMAT_R8_SRGB: return VK_FORMAT_R8_UNORM;
|
||||||
|
case VK_FORMAT_R8_UNORM: return VK_FORMAT_R8_UNORM;
|
||||||
|
case VK_FORMAT_R8G8_SRGB: return VK_FORMAT_R8G8_UNORM;
|
||||||
|
case VK_FORMAT_R8G8_UNORM: return VK_FORMAT_R8G8_UNORM;
|
||||||
|
case VK_FORMAT_R8G8B8_SRGB: return VK_FORMAT_R8G8B8_UNORM;
|
||||||
|
case VK_FORMAT_R8G8B8_UNORM: return VK_FORMAT_R8G8B8_UNORM;
|
||||||
|
case VK_FORMAT_B8G8R8_SRGB: return VK_FORMAT_B8G8R8_UNORM;
|
||||||
|
case VK_FORMAT_B8G8R8_UNORM: return VK_FORMAT_B8G8R8_UNORM;
|
||||||
|
case VK_FORMAT_R8G8B8A8_SRGB: return VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case VK_FORMAT_R8G8B8A8_UNORM: return VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
case VK_FORMAT_B8G8R8A8_SRGB: return VK_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
case VK_FORMAT_B8G8R8A8_UNORM: return VK_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
case VK_FORMAT_A8B8G8R8_SRGB_PACK32: return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||||
|
case VK_FORMAT_A8B8G8R8_UNORM_PACK32: return VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||||
|
case VK_FORMAT_BC1_RGB_SRGB_BLOCK: return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return VK_FORMAT_BC1_RGBA_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC2_SRGB_BLOCK: return VK_FORMAT_BC2_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC2_UNORM_BLOCK: return VK_FORMAT_BC2_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC3_SRGB_BLOCK: return VK_FORMAT_BC3_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC3_UNORM_BLOCK: return VK_FORMAT_BC3_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC7_SRGB_BLOCK: return VK_FORMAT_BC7_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_BC7_UNORM_BLOCK: return VK_FORMAT_BC7_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: return VK_FORMAT_ASTC_5x4_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: return VK_FORMAT_ASTC_5x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: return VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: return VK_FORMAT_ASTC_6x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: return VK_FORMAT_ASTC_6x6_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: return VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: return VK_FORMAT_ASTC_8x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: return VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: return VK_FORMAT_ASTC_8x6_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: return VK_FORMAT_ASTC_8x8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: return VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: return VK_FORMAT_ASTC_10x5_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: return VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: return VK_FORMAT_ASTC_10x6_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: return VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: return VK_FORMAT_ASTC_10x8_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: return VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: return VK_FORMAT_ASTC_10x10_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: return VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: return VK_FORMAT_ASTC_12x10_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: return VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: return VK_FORMAT_ASTC_12x12_UNORM_BLOCK;
|
||||||
|
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG: return VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG: return VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG: return VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG: return VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG: return VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG: return VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG: return VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG;
|
||||||
|
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG: return VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG;
|
||||||
|
default:
|
||||||
|
return VK_FORMAT_UNDEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create) {
|
||||||
const qboolean is_depth = !!(create->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
const qboolean is_depth = !!(create->usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
|
||||||
xvk_image_t image = {0};
|
r_vk_image_t image = {0};
|
||||||
VkMemoryRequirements memreq;
|
VkMemoryRequirements memreq;
|
||||||
|
|
||||||
|
const qboolean is_cubemap = !!(create->flags & kVkImageFlagIsCubemap);
|
||||||
|
|
||||||
|
const VkFormat unorm_format = unormFormatFor(create->format);
|
||||||
|
const qboolean create_unorm =
|
||||||
|
!!(create->flags & kVkImageFlagCreateUnormView)
|
||||||
|
&& unorm_format != VK_FORMAT_UNDEFINED
|
||||||
|
&& unorm_format != create->format;
|
||||||
|
|
||||||
VkImageCreateInfo ici = {
|
VkImageCreateInfo ici = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||||
.imageType = VK_IMAGE_TYPE_2D,
|
.imageType = VK_IMAGE_TYPE_2D,
|
||||||
|
@ -35,11 +117,15 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
||||||
.usage = create->usage,
|
.usage = create->usage,
|
||||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
.flags = create->is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0,
|
.flags = 0
|
||||||
|
| (is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0)
|
||||||
|
| (create_unorm ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image));
|
XVK_CHECK(vkCreateImage(vk_core.device, &ici, NULL, &image.image));
|
||||||
|
|
||||||
|
image.format = ici.format;
|
||||||
|
|
||||||
if (create->debug_name)
|
if (create->debug_name)
|
||||||
SET_DEBUG_NAME(image.image, VK_OBJECT_TYPE_IMAGE, create->debug_name);
|
SET_DEBUG_NAME(image.image, VK_OBJECT_TYPE_IMAGE, create->debug_name);
|
||||||
|
|
||||||
|
@ -48,9 +134,11 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
||||||
XVK_CHECK(vkBindImageMemory(vk_core.device, image.image, image.devmem.device_memory, image.devmem.offset));
|
XVK_CHECK(vkBindImageMemory(vk_core.device, image.image, image.devmem.device_memory, image.devmem.offset));
|
||||||
|
|
||||||
if (create->usage & usage_bits_implying_views) {
|
if (create->usage & usage_bits_implying_views) {
|
||||||
const VkImageViewCreateInfo ivci = {
|
const qboolean has_alpha = !!(create->flags & kVkImageFlagHasAlpha);
|
||||||
|
|
||||||
|
VkImageViewCreateInfo ivci = {
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||||
.viewType = create->is_cubemap ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D,
|
.viewType = is_cubemap ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D,
|
||||||
.format = ici.format,
|
.format = ici.format,
|
||||||
.image = image.image,
|
.image = image.image,
|
||||||
.subresourceRange.aspectMask = is_depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT,
|
.subresourceRange.aspectMask = is_depth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
@ -58,12 +146,21 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
||||||
.subresourceRange.levelCount = ici.mipLevels,
|
.subresourceRange.levelCount = ici.mipLevels,
|
||||||
.subresourceRange.baseArrayLayer = 0,
|
.subresourceRange.baseArrayLayer = 0,
|
||||||
.subresourceRange.layerCount = ici.arrayLayers,
|
.subresourceRange.layerCount = ici.arrayLayers,
|
||||||
.components = (VkComponentMapping){0, 0, 0, (is_depth || create->has_alpha) ? 0 : VK_COMPONENT_SWIZZLE_ONE},
|
// TODO component swizzling based on format, e.g. R8 -> RRRR
|
||||||
|
.components = (VkComponentMapping){0, 0, 0, (is_depth || has_alpha) ? 0 : VK_COMPONENT_SWIZZLE_ONE},
|
||||||
};
|
};
|
||||||
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view));
|
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view));
|
||||||
|
|
||||||
if (create->debug_name)
|
if (create->debug_name)
|
||||||
SET_DEBUG_NAME(image.view, VK_OBJECT_TYPE_IMAGE_VIEW, create->debug_name);
|
SET_DEBUG_NAME(image.view, VK_OBJECT_TYPE_IMAGE_VIEW, create->debug_name);
|
||||||
|
|
||||||
|
if (create_unorm) {
|
||||||
|
ivci.format = unorm_format;
|
||||||
|
XVK_CHECK(vkCreateImageView(vk_core.device, &ivci, NULL, &image.view_unorm));
|
||||||
|
|
||||||
|
if (create->debug_name)
|
||||||
|
SET_DEBUG_NAMEF(image.view_unorm, VK_OBJECT_TYPE_IMAGE_VIEW, "%s_unorm", create->debug_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
image.width = create->width;
|
image.width = create->width;
|
||||||
|
@ -73,11 +170,17 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XVK_ImageDestroy(xvk_image_t *img) {
|
void R_VkImageDestroy(r_vk_image_t *img) {
|
||||||
vkDestroyImageView(vk_core.device, img->view, NULL);
|
if (img->view_unorm != VK_NULL_HANDLE)
|
||||||
|
vkDestroyImageView(vk_core.device, img->view_unorm, NULL);
|
||||||
|
|
||||||
|
if (img->view != VK_NULL_HANDLE)
|
||||||
|
vkDestroyImageView(vk_core.device, img->view, NULL);
|
||||||
|
|
||||||
vkDestroyImage(vk_core.device, img->image, NULL);
|
vkDestroyImage(vk_core.device, img->image, NULL);
|
||||||
|
|
||||||
VK_DevMemFree(&img->devmem);
|
VK_DevMemFree(&img->devmem);
|
||||||
*img = (xvk_image_t){0};
|
*img = (r_vk_image_t){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
void R_VkImageClear(VkCommandBuffer cmdbuf, VkImage image) {
|
void R_VkImageClear(VkCommandBuffer cmdbuf, VkImage image) {
|
||||||
|
@ -185,3 +288,368 @@ void R_VkImageBlit(VkCommandBuffer cmdbuf, const r_vkimage_blit_args *blit_args)
|
||||||
0, 0, NULL, 0, NULL, COUNTOF(image_barriers), image_barriers);
|
0, 0, NULL, 0, NULL, COUNTOF(image_barriers), image_barriers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t R_VkImageFormatTexelBlockSize( VkFormat format ) {
|
||||||
|
switch (format) {
|
||||||
|
case VK_FORMAT_R4G4_UNORM_PACK8:
|
||||||
|
case VK_FORMAT_R8_UNORM:
|
||||||
|
case VK_FORMAT_R8_SNORM:
|
||||||
|
case VK_FORMAT_R8_USCALED:
|
||||||
|
case VK_FORMAT_R8_SSCALED:
|
||||||
|
case VK_FORMAT_R8_UINT:
|
||||||
|
case VK_FORMAT_R8_SINT:
|
||||||
|
case VK_FORMAT_R8_SRGB:
|
||||||
|
return 1;
|
||||||
|
case VK_FORMAT_R10X6_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_R12X4_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_A4R4G4B4_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_A4B4G4R4_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_B5G6R5_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
||||||
|
case VK_FORMAT_R8G8_UNORM:
|
||||||
|
case VK_FORMAT_R8G8_SNORM:
|
||||||
|
case VK_FORMAT_R8G8_USCALED:
|
||||||
|
case VK_FORMAT_R8G8_SSCALED:
|
||||||
|
case VK_FORMAT_R8G8_UINT:
|
||||||
|
case VK_FORMAT_R8G8_SINT:
|
||||||
|
case VK_FORMAT_R8G8_SRGB:
|
||||||
|
case VK_FORMAT_R16_UNORM:
|
||||||
|
case VK_FORMAT_R16_SNORM:
|
||||||
|
case VK_FORMAT_R16_USCALED:
|
||||||
|
case VK_FORMAT_R16_SSCALED:
|
||||||
|
case VK_FORMAT_R16_UINT:
|
||||||
|
case VK_FORMAT_R16_SINT:
|
||||||
|
case VK_FORMAT_R16_SFLOAT:
|
||||||
|
return 2;
|
||||||
|
case VK_FORMAT_R8G8B8_UNORM:
|
||||||
|
case VK_FORMAT_R8G8B8_SNORM:
|
||||||
|
case VK_FORMAT_R8G8B8_USCALED:
|
||||||
|
case VK_FORMAT_R8G8B8_SSCALED:
|
||||||
|
case VK_FORMAT_R8G8B8_UINT:
|
||||||
|
case VK_FORMAT_R8G8B8_SINT:
|
||||||
|
case VK_FORMAT_R8G8B8_SRGB:
|
||||||
|
case VK_FORMAT_B8G8R8_UNORM:
|
||||||
|
case VK_FORMAT_B8G8R8_SNORM:
|
||||||
|
case VK_FORMAT_B8G8R8_USCALED:
|
||||||
|
case VK_FORMAT_B8G8R8_SSCALED:
|
||||||
|
case VK_FORMAT_B8G8R8_UINT:
|
||||||
|
case VK_FORMAT_B8G8R8_SINT:
|
||||||
|
case VK_FORMAT_B8G8R8_SRGB:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
|
||||||
|
case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
|
||||||
|
case VK_FORMAT_R16G16_S10_5_NV:
|
||||||
|
case VK_FORMAT_R8G8B8A8_UNORM:
|
||||||
|
case VK_FORMAT_R8G8B8A8_SNORM:
|
||||||
|
case VK_FORMAT_R8G8B8A8_USCALED:
|
||||||
|
case VK_FORMAT_R8G8B8A8_SSCALED:
|
||||||
|
case VK_FORMAT_R8G8B8A8_UINT:
|
||||||
|
case VK_FORMAT_R8G8B8A8_SINT:
|
||||||
|
case VK_FORMAT_R8G8B8A8_SRGB:
|
||||||
|
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||||
|
case VK_FORMAT_B8G8R8A8_SNORM:
|
||||||
|
case VK_FORMAT_B8G8R8A8_USCALED:
|
||||||
|
case VK_FORMAT_B8G8R8A8_SSCALED:
|
||||||
|
case VK_FORMAT_B8G8R8A8_UINT:
|
||||||
|
case VK_FORMAT_B8G8R8A8_SINT:
|
||||||
|
case VK_FORMAT_B8G8R8A8_SRGB:
|
||||||
|
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
|
||||||
|
case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
|
||||||
|
case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
|
||||||
|
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
|
||||||
|
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
|
||||||
|
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
|
||||||
|
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
|
||||||
|
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
|
||||||
|
case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
|
||||||
|
case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
|
||||||
|
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
|
||||||
|
case VK_FORMAT_A2R10G10B10_UINT_PACK32:
|
||||||
|
case VK_FORMAT_A2R10G10B10_SINT_PACK32:
|
||||||
|
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
|
||||||
|
case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
|
||||||
|
case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
|
||||||
|
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
|
||||||
|
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
|
||||||
|
case VK_FORMAT_A2B10G10R10_SINT_PACK32:
|
||||||
|
case VK_FORMAT_R16G16_UNORM:
|
||||||
|
case VK_FORMAT_R16G16_SNORM:
|
||||||
|
case VK_FORMAT_R16G16_USCALED:
|
||||||
|
case VK_FORMAT_R16G16_SSCALED:
|
||||||
|
case VK_FORMAT_R16G16_UINT:
|
||||||
|
case VK_FORMAT_R16G16_SINT:
|
||||||
|
case VK_FORMAT_R16G16_SFLOAT:
|
||||||
|
case VK_FORMAT_R32_UINT:
|
||||||
|
case VK_FORMAT_R32_SINT:
|
||||||
|
case VK_FORMAT_R32_SFLOAT:
|
||||||
|
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
|
||||||
|
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
|
||||||
|
return 4;
|
||||||
|
case VK_FORMAT_R16G16B16_UNORM:
|
||||||
|
case VK_FORMAT_R16G16B16_SNORM:
|
||||||
|
case VK_FORMAT_R16G16B16_USCALED:
|
||||||
|
case VK_FORMAT_R16G16B16_SSCALED:
|
||||||
|
case VK_FORMAT_R16G16B16_UINT:
|
||||||
|
case VK_FORMAT_R16G16B16_SINT:
|
||||||
|
case VK_FORMAT_R16G16B16_SFLOAT:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_R16G16B16A16_UNORM:
|
||||||
|
case VK_FORMAT_R16G16B16A16_SNORM:
|
||||||
|
case VK_FORMAT_R16G16B16A16_USCALED:
|
||||||
|
case VK_FORMAT_R16G16B16A16_SSCALED:
|
||||||
|
case VK_FORMAT_R16G16B16A16_UINT:
|
||||||
|
case VK_FORMAT_R16G16B16A16_SINT:
|
||||||
|
case VK_FORMAT_R16G16B16A16_SFLOAT:
|
||||||
|
case VK_FORMAT_R32G32_UINT:
|
||||||
|
case VK_FORMAT_R32G32_SINT:
|
||||||
|
case VK_FORMAT_R32G32_SFLOAT:
|
||||||
|
case VK_FORMAT_R64_UINT:
|
||||||
|
case VK_FORMAT_R64_SINT:
|
||||||
|
case VK_FORMAT_R64_SFLOAT:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_R32G32B32_UINT:
|
||||||
|
case VK_FORMAT_R32G32B32_SINT:
|
||||||
|
case VK_FORMAT_R32G32B32_SFLOAT:
|
||||||
|
return 12;
|
||||||
|
case VK_FORMAT_R32G32B32A32_UINT:
|
||||||
|
case VK_FORMAT_R32G32B32A32_SINT:
|
||||||
|
case VK_FORMAT_R32G32B32A32_SFLOAT:
|
||||||
|
case VK_FORMAT_R64G64_UINT:
|
||||||
|
case VK_FORMAT_R64G64_SINT:
|
||||||
|
case VK_FORMAT_R64G64_SFLOAT:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_R64G64B64_UINT:
|
||||||
|
case VK_FORMAT_R64G64B64_SINT:
|
||||||
|
case VK_FORMAT_R64G64B64_SFLOAT:
|
||||||
|
return 24;
|
||||||
|
case VK_FORMAT_R64G64B64A64_UINT:
|
||||||
|
case VK_FORMAT_R64G64B64A64_SINT:
|
||||||
|
case VK_FORMAT_R64G64B64A64_SFLOAT:
|
||||||
|
return 32;
|
||||||
|
|
||||||
|
case VK_FORMAT_D16_UNORM:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case VK_FORMAT_X8_D24_UNORM_PACK32:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case VK_FORMAT_D32_SFLOAT:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case VK_FORMAT_S8_UINT:
|
||||||
|
return 2;
|
||||||
|
|
||||||
|
case VK_FORMAT_D16_UNORM_S8_UINT:
|
||||||
|
return 3;
|
||||||
|
|
||||||
|
case VK_FORMAT_D24_UNORM_S8_UINT:
|
||||||
|
return 4;
|
||||||
|
|
||||||
|
case VK_FORMAT_D32_SFLOAT_S8_UINT:
|
||||||
|
return 5;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC1_RGB_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC1_RGB_SRGB_BLOCK:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC1_RGBA_SRGB_BLOCK:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC2_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC2_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC3_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC3_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC4_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC4_SNORM_BLOCK:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC5_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC5_SNORM_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC6H_UFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_BC6H_SFLOAT_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_BC7_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_BC7_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_EAC_R11_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_EAC_R11_SNORM_BLOCK:
|
||||||
|
return 8;
|
||||||
|
|
||||||
|
case VK_FORMAT_EAC_R11G11_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_EAC_R11G11_SNORM_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_4x4_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_5x4_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_5x4_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_5x5_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_5x5_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_6x5_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_6x5_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_6x6_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_6x6_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
|
||||||
|
case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_8x5_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_8x5_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_8x6_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_8x6_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_8x8_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_8x8_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x5_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x5_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x6_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x6_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x8_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x8_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x10_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_10x10_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_12x10_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
|
||||||
|
case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
|
||||||
|
return 16;
|
||||||
|
case VK_FORMAT_G8B8G8R8_422_UNORM:
|
||||||
|
return 4;
|
||||||
|
case VK_FORMAT_B8G8R8G8_422_UNORM:
|
||||||
|
return 4;
|
||||||
|
case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G16B16G16R16_422_UNORM:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_B16G16R16G16_422_UNORM:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
|
||||||
|
case VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
|
||||||
|
case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
|
||||||
|
case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG:
|
||||||
|
case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
|
||||||
|
return 8;
|
||||||
|
case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
|
||||||
|
return 3;
|
||||||
|
case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
|
||||||
|
return 6;
|
||||||
|
case VK_FORMAT_UNDEFINED:
|
||||||
|
case VK_FORMAT_MAX_ENUM:
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
|
@ -2,14 +2,25 @@
|
||||||
#include "vk_core.h"
|
#include "vk_core.h"
|
||||||
#include "vk_devmem.h"
|
#include "vk_devmem.h"
|
||||||
|
|
||||||
typedef struct xvk_image_s {
|
typedef struct r_vk_image_s {
|
||||||
vk_devmem_t devmem;
|
vk_devmem_t devmem;
|
||||||
VkImage image;
|
VkImage image;
|
||||||
VkImageView view;
|
VkImageView view;
|
||||||
|
|
||||||
|
// Optional, created by kVkImageFlagCreateUnormView
|
||||||
|
// Used for sRGB-γ-unaware traditional renderer
|
||||||
|
VkImageView view_unorm;
|
||||||
|
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
int mips;
|
int mips;
|
||||||
} xvk_image_t;
|
VkFormat format;
|
||||||
|
} r_vk_image_t;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kVkImageFlagHasAlpha = (1<<0),
|
||||||
|
kVkImageFlagIsCubemap = (1<<1),
|
||||||
|
kVkImageFlagCreateUnormView = (1<<2),
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *debug_name;
|
const char *debug_name;
|
||||||
|
@ -18,13 +29,12 @@ typedef struct {
|
||||||
VkFormat format;
|
VkFormat format;
|
||||||
VkImageTiling tiling;
|
VkImageTiling tiling;
|
||||||
VkImageUsageFlags usage;
|
VkImageUsageFlags usage;
|
||||||
qboolean has_alpha;
|
|
||||||
qboolean is_cubemap;
|
|
||||||
VkMemoryPropertyFlags memory_props;
|
VkMemoryPropertyFlags memory_props;
|
||||||
} xvk_image_create_t;
|
uint32_t flags;
|
||||||
|
} r_vk_image_create_t;
|
||||||
|
|
||||||
xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create);
|
r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create);
|
||||||
void XVK_ImageDestroy(xvk_image_t *img);
|
void R_VkImageDestroy(r_vk_image_t *img);
|
||||||
|
|
||||||
void R_VkImageClear(VkCommandBuffer cmdbuf, VkImage image);
|
void R_VkImageClear(VkCommandBuffer cmdbuf, VkImage image);
|
||||||
|
|
||||||
|
@ -40,3 +50,4 @@ typedef struct {
|
||||||
|
|
||||||
void R_VkImageBlit( VkCommandBuffer cmdbuf, const r_vkimage_blit_args *blit_args );
|
void R_VkImageBlit( VkCommandBuffer cmdbuf, const r_vkimage_blit_args *blit_args );
|
||||||
|
|
||||||
|
uint32_t R_VkImageFormatTexelBlockSize( VkFormat format );
|
||||||
|
|
|
@ -1263,6 +1263,7 @@ static void uploadPointLights( struct LightsMetadata *metadata ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
vk_lights_bindings_t VK_LightsUpload( void ) {
|
vk_lights_bindings_t VK_LightsUpload( void ) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(upload, __FUNCTION__);
|
||||||
const vk_staging_region_t locked = R_VkStagingLockForBuffer( (vk_staging_buffer_args_t) {
|
const vk_staging_region_t locked = R_VkStagingLockForBuffer( (vk_staging_buffer_args_t) {
|
||||||
.buffer = g_lights_.buffer.buffer,
|
.buffer = g_lights_.buffer.buffer,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
|
@ -1287,6 +1288,8 @@ vk_lights_bindings_t VK_LightsUpload( void ) {
|
||||||
|
|
||||||
g_lights_.frame_sequence++;
|
g_lights_.frame_sequence++;
|
||||||
|
|
||||||
|
APROF_SCOPE_END(upload);
|
||||||
|
|
||||||
return (vk_lights_bindings_t){
|
return (vk_lights_bindings_t){
|
||||||
.buffer = g_lights_.buffer.buffer,
|
.buffer = g_lights_.buffer.buffer,
|
||||||
.metadata = {
|
.metadata = {
|
||||||
|
|
|
@ -11,33 +11,67 @@
|
||||||
|
|
||||||
#define MAX_INCLUDE_DEPTH 4
|
#define MAX_INCLUDE_DEPTH 4
|
||||||
|
|
||||||
|
#define MAX_MATERIALS 2048
|
||||||
|
|
||||||
static r_vk_material_t k_default_material = {
|
static r_vk_material_t k_default_material = {
|
||||||
.tex_base_color = -1,
|
.tex_base_color = -1,
|
||||||
.tex_metalness = 0,
|
.tex_metalness = 0,
|
||||||
.tex_roughness = 0,
|
.tex_roughness = 0,
|
||||||
.tex_normalmap = 0,
|
.tex_normalmap = 0,
|
||||||
|
|
||||||
.metalness = 0.f,
|
.metalness = 0.f,
|
||||||
.roughness = 1.f,
|
.roughness = 1.f,
|
||||||
.normal_scale = 1.f,
|
.normal_scale = 1.f,
|
||||||
.base_color = { 1.f, 1.f, 1.f, 1.f },
|
.base_color = { 1.f, 1.f, 1.f, 1.f },
|
||||||
|
|
||||||
.set = false,
|
.set = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
enum {
|
||||||
|
#define X(bit, type, name, key, func) kMatField_##key = (1 << (bit)),
|
||||||
|
MATERIAL_FIELDS_LIST(X)
|
||||||
|
#undef X
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
#define MAX_RENDERMODE_MATERIALS 32
|
#define MAX_RENDERMODE_MATERIALS 32
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct {
|
struct {
|
||||||
int tex_id;
|
int tex_id;
|
||||||
r_vk_material_t mat;
|
r_vk_material_ref_t mat;
|
||||||
} materials[MAX_RENDERMODE_MATERIALS];
|
} map[MAX_RENDERMODE_MATERIALS];
|
||||||
int count;
|
int count;
|
||||||
} r_vk_material_per_mode_t;
|
} r_vk_material_per_mode_t;
|
||||||
|
|
||||||
static struct {
|
enum {
|
||||||
r_vk_material_t materials[MAX_TEXTURES];
|
kMaterialNotChecked = 0,
|
||||||
|
kMaterialNoReplacement = -1,
|
||||||
|
};
|
||||||
|
|
||||||
r_vk_material_per_mode_t rendermode[kRenderTransAdd+1];
|
typedef struct {
|
||||||
|
int mat_id;
|
||||||
|
|
||||||
|
// TODO rendermode chain
|
||||||
|
} texture_to_material_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
//int for_tex_id;
|
||||||
|
string name;
|
||||||
|
|
||||||
|
r_vk_material_t material;
|
||||||
|
} material_entry_t;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int count;
|
||||||
|
material_entry_t table[MAX_MATERIALS];
|
||||||
|
|
||||||
|
texture_to_material_t tex_to_mat[MAX_TEXTURES];
|
||||||
|
|
||||||
|
// TODO embed into tex_to_mat
|
||||||
|
r_vk_material_per_mode_t for_rendermode[kRenderTransAdd+1];
|
||||||
|
|
||||||
|
// TODO for name
|
||||||
} g_materials;
|
} g_materials;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
@ -49,9 +83,9 @@ static struct {
|
||||||
uint64_t texture_load_duration_ns;
|
uint64_t texture_load_duration_ns;
|
||||||
} g_stats;
|
} g_stats;
|
||||||
|
|
||||||
static int loadTexture( const char *filename, qboolean force_reload ) {
|
static int loadTexture( const char *filename, qboolean force_reload, colorspace_hint_e colorspace ) {
|
||||||
const uint64_t load_begin_ns = aprof_time_now_ns();
|
const uint64_t load_begin_ns = aprof_time_now_ns();
|
||||||
const int tex_id = force_reload ? XVK_LoadTextureReplace( filename, NULL, 0, 0 ) : VK_LoadTexture( filename, NULL, 0, 0 );
|
const int tex_id = R_VkLoadTexture( filename, colorspace, force_reload);
|
||||||
DEBUG("Loaded texture %s => %d", filename, tex_id);
|
DEBUG("Loaded texture %s => %d", filename, tex_id);
|
||||||
g_stats.texture_loads++;
|
g_stats.texture_loads++;
|
||||||
g_stats.texture_load_duration_ns += aprof_time_now_ns() - load_begin_ns;
|
g_stats.texture_load_duration_ns += aprof_time_now_ns() - load_begin_ns;
|
||||||
|
@ -71,23 +105,66 @@ static void makePath(char *out, size_t out_size, const char *value, const char *
|
||||||
#define MAKE_PATH(out, value) \
|
#define MAKE_PATH(out, value) \
|
||||||
makePath(out, sizeof(out), value, path_begin, path_end)
|
makePath(out, sizeof(out), value, path_begin, path_end)
|
||||||
|
|
||||||
static void loadMaterialsFromFile( const char *filename, int depth ) {
|
static void printMaterial(int index) {
|
||||||
fs_offset_t size;
|
const char* const name = g_materials.table[index].name;
|
||||||
const char *const path_begin = filename;
|
const r_vk_material_t* const mat = &g_materials.table[index].material;
|
||||||
const char *path_end = Q_strrchr(filename, '/');
|
|
||||||
|
|
||||||
|
DEBUG("material[%d] \"%s\" (tbc=%d, tr=%d, tm=%d, tn=%d bc=(%.03f,%.03f,%.03f,%.03f) r=%.03f m=%.03f ns=%.03f",
|
||||||
|
index, name,
|
||||||
|
mat->tex_base_color, mat->tex_roughness, mat->tex_metalness, mat->tex_normalmap,
|
||||||
|
mat->base_color[0], mat->base_color[1], mat->base_color[2], mat->base_color[3],
|
||||||
|
mat->roughness, mat->metalness, mat->normal_scale
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int addMaterial(const char *name, const r_vk_material_t* mat) {
|
||||||
|
if (g_materials.count == MAX_MATERIALS) {
|
||||||
|
ERR("Max count of materials %d reached", MAX_MATERIALS);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_strncpy(g_materials.table[g_materials.count].name, name, sizeof g_materials.table[g_materials.count].name);
|
||||||
|
g_materials.table[g_materials.count].material = *mat;
|
||||||
|
|
||||||
|
printMaterial(g_materials.count);
|
||||||
|
|
||||||
|
return g_materials.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void assignMaterialForTexture(const char *name, int for_tex_id, int mat_id) {
|
||||||
|
const char* const tex_name = findTexture(for_tex_id)->name;
|
||||||
|
DEBUG("Assigning material \"%s\" for_tex_id=\"%s\"(%d)", name, tex_name, for_tex_id);
|
||||||
|
|
||||||
|
ASSERT(mat_id >= 0);
|
||||||
|
ASSERT(mat_id < g_materials.count);
|
||||||
|
|
||||||
|
ASSERT(for_tex_id < COUNTOF(g_materials.tex_to_mat));
|
||||||
|
texture_to_material_t* const t2m = g_materials.tex_to_mat + for_tex_id;
|
||||||
|
|
||||||
|
if (t2m->mat_id == kMaterialNoReplacement) {
|
||||||
|
ERR("Texture \"%s\"(%d) has been already queried by something. Only future queries will get the new material", tex_name, for_tex_id);
|
||||||
|
} else if (t2m->mat_id != kMaterialNotChecked) {
|
||||||
|
ERR("Texture \"%s\"(%d) already has material assigned, will replace", tex_name, for_tex_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
t2m->mat_id = mat_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadMaterialsFromFile( const char *filename, int depth ) {
|
||||||
const uint64_t load_file_begin_ns = aprof_time_now_ns();
|
const uint64_t load_file_begin_ns = aprof_time_now_ns();
|
||||||
byte *data = gEngine.fsapi->LoadFile( filename, 0, false );
|
byte *data = gEngine.fsapi->LoadFile( filename, 0, false );
|
||||||
g_stats.material_file_read_duration_ns += aprof_time_now_ns() - load_file_begin_ns;
|
g_stats.material_file_read_duration_ns += aprof_time_now_ns() - load_file_begin_ns;
|
||||||
|
|
||||||
char *pos = (char*)data;
|
|
||||||
r_vk_material_t current_material = k_default_material;
|
r_vk_material_t current_material = k_default_material;
|
||||||
int current_material_index = -1;
|
int for_tex_id = -1;
|
||||||
|
int dummy_named_texture_fixme = -1;
|
||||||
qboolean force_reload = false;
|
qboolean force_reload = false;
|
||||||
qboolean create = false;
|
qboolean create = false;
|
||||||
qboolean metalness_set = false;
|
qboolean metalness_set = false;
|
||||||
|
|
||||||
|
string name;
|
||||||
string basecolor_map, normal_map, metal_map, roughness_map;
|
string basecolor_map, normal_map, metal_map, roughness_map;
|
||||||
|
//uint32_t fields;
|
||||||
|
|
||||||
int rendermode = 0;
|
int rendermode = 0;
|
||||||
|
|
||||||
|
@ -96,11 +173,14 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
|
||||||
if ( !data )
|
if ( !data )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const char *const path_begin = filename;
|
||||||
|
const char *path_end = Q_strrchr(filename, '/');
|
||||||
if ( !path_end )
|
if ( !path_end )
|
||||||
path_end = path_begin;
|
path_end = path_begin;
|
||||||
else
|
else
|
||||||
path_end++;
|
path_end++;
|
||||||
|
|
||||||
|
char *pos = (char*)data;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char key[1024];
|
char key[1024];
|
||||||
char value[1024];
|
char value[1024];
|
||||||
|
@ -113,24 +193,34 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
|
||||||
|
|
||||||
if (key[0] == '{') {
|
if (key[0] == '{') {
|
||||||
current_material = k_default_material;
|
current_material = k_default_material;
|
||||||
current_material_index = -1;
|
for_tex_id = -1;
|
||||||
|
dummy_named_texture_fixme = -1;
|
||||||
force_reload = false;
|
force_reload = false;
|
||||||
create = false;
|
create = false;
|
||||||
metalness_set = false;
|
metalness_set = false;
|
||||||
basecolor_map[0] = normal_map[0] = metal_map[0] = roughness_map[0] = '\0';
|
name[0] = basecolor_map[0] = normal_map[0] = metal_map[0] = roughness_map[0] = '\0';
|
||||||
rendermode = 0;
|
rendermode = 0;
|
||||||
|
//fields = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key[0] == '}') {
|
if (key[0] == '}') {
|
||||||
if (current_material_index < 0)
|
if (for_tex_id < 0 && !create) {
|
||||||
|
// Skip this material, as its texture hasn't been loaded
|
||||||
|
// NOTE: might want to check whether it makes sense wrt late-loading stuff
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#define LOAD_TEXTURE_FOR(name, field) do { \
|
if (!name[0]) {
|
||||||
|
WARN("Unreferenceable (no \"for_texture\", no \"new\") material found in %s", filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define LOAD_TEXTURE_FOR(name, field, colorspace) do { \
|
||||||
if (name[0] != '\0') { \
|
if (name[0] != '\0') { \
|
||||||
char texture_path[256]; \
|
char texture_path[256]; \
|
||||||
MAKE_PATH(texture_path, name); \
|
MAKE_PATH(texture_path, name); \
|
||||||
const int tex_id = loadTexture(texture_path, force_reload); \
|
const int tex_id = loadTexture(texture_path, force_reload, colorspace); \
|
||||||
if (tex_id < 0) { \
|
if (tex_id < 0) { \
|
||||||
ERR("Failed to load texture \"%s\" for "#name"", name); \
|
ERR("Failed to load texture \"%s\" for "#name"", name); \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -138,65 +228,76 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
|
||||||
} \
|
} \
|
||||||
}} while(0)
|
}} while(0)
|
||||||
|
|
||||||
LOAD_TEXTURE_FOR(basecolor_map, tex_base_color);
|
LOAD_TEXTURE_FOR(basecolor_map, tex_base_color, kColorspaceNative);
|
||||||
LOAD_TEXTURE_FOR(normal_map, tex_normalmap);
|
LOAD_TEXTURE_FOR(normal_map, tex_normalmap, kColorspaceLinear);
|
||||||
LOAD_TEXTURE_FOR(metal_map, tex_metalness);
|
LOAD_TEXTURE_FOR(metal_map, tex_metalness, kColorspaceLinear);
|
||||||
LOAD_TEXTURE_FOR(roughness_map, tex_roughness);
|
LOAD_TEXTURE_FOR(roughness_map, tex_roughness, kColorspaceLinear);
|
||||||
|
|
||||||
// If there's no explicit basecolor_map value, use the "for" target texture
|
// If there's no explicit basecolor_map value, use the "for" target texture
|
||||||
if (current_material.tex_base_color == -1)
|
if (current_material.tex_base_color == -1)
|
||||||
current_material.tex_base_color = current_material_index;
|
current_material.tex_base_color = for_tex_id >= 0 ? for_tex_id : 0;
|
||||||
|
|
||||||
if (metalness_set && current_material.tex_metalness == tglob.blackTexture) {
|
if (!metalness_set && current_material.tex_metalness != tglob.whiteTexture) {
|
||||||
// Set metalness texture to white to accommodate explicitly set metalness value
|
|
||||||
current_material.tex_metalness = tglob.whiteTexture;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!metalness_set && current_material.tex_metalness != tglob.blackTexture) {
|
|
||||||
// If metalness factor wasn't set explicitly, but texture was specified, set it to match the texture value.
|
// If metalness factor wasn't set explicitly, but texture was specified, set it to match the texture value.
|
||||||
current_material.metalness = 1.f;
|
current_material.metalness = 1.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("Creating%s material for texture %s(%d)", create?" new":"",
|
const int mat_id = addMaterial(name, ¤t_material);
|
||||||
findTexture(current_material_index)->name, current_material_index);
|
|
||||||
|
|
||||||
// Assign rendermode-specific materials
|
if (mat_id < 0) {
|
||||||
if (rendermode > 0) {
|
ERR("Cannot add material \"%s\" for_tex_id=\"%s\"(%d)", name, for_tex_id >= 0 ? findTexture(for_tex_id)->name : "N/A", for_tex_id);
|
||||||
r_vk_material_per_mode_t* const rm = g_materials.rendermode + rendermode;
|
continue;
|
||||||
if (rm->count == COUNTOF(rm->materials)) {
|
|
||||||
ERR("Too many rendermode/tex_id mappings");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Adding material %d for rendermode %d", current_material_index, rendermode);
|
|
||||||
|
|
||||||
// TODO proper texid-vs-material-index
|
|
||||||
rm->materials[rm->count].tex_id = current_material_index;
|
|
||||||
rm->materials[rm->count].mat = current_material;
|
|
||||||
rm->materials[rm->count].mat.set = true;
|
|
||||||
rm->count++;
|
|
||||||
} else {
|
|
||||||
DEBUG("Creating%s material for texture %s(%d)", create?" new":"",
|
|
||||||
findTexture(current_material_index)->name, current_material_index);
|
|
||||||
|
|
||||||
g_materials.materials[current_material_index] = current_material;
|
|
||||||
g_materials.materials[current_material_index].set = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME have a personal hash map, don't use texture
|
||||||
|
if (dummy_named_texture_fixme > 0) {
|
||||||
|
assignMaterialForTexture(name, dummy_named_texture_fixme, mat_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign from-texture mapping if there's a texture
|
||||||
|
if (for_tex_id >= 0) {
|
||||||
|
// Assign rendermode-specific materials
|
||||||
|
if (rendermode > 0) {
|
||||||
|
const char* const tex_name = findTexture(for_tex_id)->name;
|
||||||
|
DEBUG("Adding material \"%s\" for_tex_id=\"%s\"(%d) for rendermode %d", name, tex_name, for_tex_id, rendermode);
|
||||||
|
|
||||||
|
r_vk_material_per_mode_t* const rm = g_materials.for_rendermode + rendermode;
|
||||||
|
if (rm->count == COUNTOF(rm->map)) {
|
||||||
|
ERR("Too many rendermode/tex_id mappings");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rm->map[rm->count].tex_id = for_tex_id;
|
||||||
|
rm->map[rm->count].mat.index = mat_id;
|
||||||
|
rm->count++;
|
||||||
|
} else {
|
||||||
|
assignMaterialForTexture(name, for_tex_id, mat_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
} // if (key[0] == '}') -- closing material block
|
||||||
|
|
||||||
pos = COM_ParseFile(pos, value, sizeof(value));
|
pos = COM_ParseFile(pos, value, sizeof(value));
|
||||||
if (!pos)
|
if (!pos)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (Q_stricmp(key, "for") == 0) {
|
if (Q_stricmp(key, "for") == 0) {
|
||||||
|
if (name[0] != '\0')
|
||||||
|
WARN("Material already has \"new\" or \"for_texture\" old=\"%s\" new=\"%s\"", name, value);
|
||||||
|
|
||||||
const uint64_t lookup_begin_ns = aprof_time_now_ns();
|
const uint64_t lookup_begin_ns = aprof_time_now_ns();
|
||||||
current_material_index = XVK_FindTextureNamedLike(value);
|
for_tex_id = XVK_FindTextureNamedLike(value);
|
||||||
g_stats.texture_lookup_duration_ns += aprof_time_now_ns() - lookup_begin_ns;
|
g_stats.texture_lookup_duration_ns += aprof_time_now_ns() - lookup_begin_ns;
|
||||||
g_stats.texture_lookups++;
|
g_stats.texture_lookups++;
|
||||||
create = false;
|
Q_strncpy(name, value, sizeof name);
|
||||||
} else if (Q_stricmp(key, "new") == 0) {
|
} else if (Q_stricmp(key, "new") == 0) {
|
||||||
current_material_index = XVK_CreateDummyTexture(value);
|
if (name[0] != '\0')
|
||||||
|
WARN("Material already has \"new\" or \"for_texture\" old=\"%s\" new=\"%s\"", name, value);
|
||||||
|
|
||||||
|
// TODO hash map here, don't depend on textures
|
||||||
|
dummy_named_texture_fixme = XVK_CreateDummyTexture(value);
|
||||||
|
Q_strncpy(name, value, sizeof name);
|
||||||
create = true;
|
create = true;
|
||||||
} else if (Q_stricmp(key, "force_reload") == 0) {
|
} else if (Q_stricmp(key, "force_reload") == 0) {
|
||||||
force_reload = Q_atoi(value) != 0;
|
force_reload = Q_atoi(value) != 0;
|
||||||
|
@ -212,26 +313,43 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
|
||||||
int *tex_id_dest = NULL;
|
int *tex_id_dest = NULL;
|
||||||
if (Q_stricmp(key, "basecolor_map") == 0) {
|
if (Q_stricmp(key, "basecolor_map") == 0) {
|
||||||
Q_strncpy(basecolor_map, value, sizeof(basecolor_map));
|
Q_strncpy(basecolor_map, value, sizeof(basecolor_map));
|
||||||
|
//fields |= kMatField_basecolor_map;
|
||||||
} else if (Q_stricmp(key, "normal_map") == 0) {
|
} else if (Q_stricmp(key, "normal_map") == 0) {
|
||||||
Q_strncpy(normal_map, value, sizeof(normal_map));
|
Q_strncpy(normal_map, value, sizeof(normal_map));
|
||||||
|
//fields |= kMatField_normal_map;
|
||||||
} else if (Q_stricmp(key, "metal_map") == 0) {
|
} else if (Q_stricmp(key, "metal_map") == 0) {
|
||||||
Q_strncpy(metal_map, value, sizeof(metal_map));
|
Q_strncpy(metal_map, value, sizeof(metal_map));
|
||||||
|
//fields |= kMatField_metal_map;
|
||||||
} else if (Q_stricmp(key, "roughness_map") == 0) {
|
} else if (Q_stricmp(key, "roughness_map") == 0) {
|
||||||
Q_strncpy(roughness_map, value, sizeof(roughness_map));
|
Q_strncpy(roughness_map, value, sizeof(roughness_map));
|
||||||
|
//fields |= kMatField_roughness_map;
|
||||||
|
} else if (Q_stricmp(key, "inherit") == 0 || Q_stricmp(key, "use") == 0) {
|
||||||
|
const r_vk_material_ref_t ref = R_VkMaterialGetForName(value);
|
||||||
|
if (ref.index < 0) {
|
||||||
|
ERR("In material \"%s\" cannot find material \"%s\" to inherit", name, value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const r_vk_material_t inherited = R_VkMaterialGetForRef(ref);
|
||||||
|
current_material = inherited;
|
||||||
} else if (Q_stricmp(key, "roughness") == 0) {
|
} else if (Q_stricmp(key, "roughness") == 0) {
|
||||||
sscanf(value, "%f", ¤t_material.roughness);
|
sscanf(value, "%f", ¤t_material.roughness);
|
||||||
|
//fields |= kMatField_roughness;
|
||||||
} else if (Q_stricmp(key, "metalness") == 0) {
|
} else if (Q_stricmp(key, "metalness") == 0) {
|
||||||
sscanf(value, "%f", ¤t_material.metalness);
|
sscanf(value, "%f", ¤t_material.metalness);
|
||||||
|
//fields |= kMatField_metalness;
|
||||||
metalness_set = true;
|
metalness_set = true;
|
||||||
} else if (Q_stricmp(key, "normal_scale") == 0) {
|
} else if (Q_stricmp(key, "normal_scale") == 0) {
|
||||||
sscanf(value, "%f", ¤t_material.normal_scale);
|
sscanf(value, "%f", ¤t_material.normal_scale);
|
||||||
|
//fields |= kMatField_normal_scale;
|
||||||
} else if (Q_stricmp(key, "base_color") == 0) {
|
} else if (Q_stricmp(key, "base_color") == 0) {
|
||||||
sscanf(value, "%f %f %f %f", ¤t_material.base_color[0], ¤t_material.base_color[1], ¤t_material.base_color[2], ¤t_material.base_color[3]);
|
sscanf(value, "%f %f %f %f", ¤t_material.base_color[0], ¤t_material.base_color[1], ¤t_material.base_color[2], ¤t_material.base_color[3]);
|
||||||
|
//fields |= kMatField_base_color;
|
||||||
} else if (Q_stricmp(key, "for_rendermode") == 0) {
|
} else if (Q_stricmp(key, "for_rendermode") == 0) {
|
||||||
rendermode = R_VkRenderModeFromString(value);
|
rendermode = R_VkRenderModeFromString(value);
|
||||||
if (rendermode < 0)
|
if (rendermode < 0)
|
||||||
ERR("Invalid rendermode \"%s\"", value);
|
ERR("Invalid rendermode \"%s\"", value);
|
||||||
ASSERT(rendermode < COUNTOF(g_materials.rendermode[0].materials));
|
ASSERT(rendermode < COUNTOF(g_materials.for_rendermode[0].map));
|
||||||
|
//fields |= kMatField_rendermode;
|
||||||
} else {
|
} else {
|
||||||
ERR("Unknown material key \"%s\" on line `%.*s`", key, (int)(pos - line_begin), line_begin);
|
ERR("Unknown material key \"%s\" on line `%.*s`", key, (int)(pos - line_begin), line_begin);
|
||||||
continue;
|
continue;
|
||||||
|
@ -267,26 +385,27 @@ static int findFilenameExtension(const char *s, int len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void R_VkMaterialsReload( void ) {
|
void R_VkMaterialsReload( void ) {
|
||||||
memset(&g_stats, 0, sizeof(g_stats));
|
|
||||||
const uint64_t begin_time_ns = aprof_time_now_ns();
|
const uint64_t begin_time_ns = aprof_time_now_ns();
|
||||||
|
memset(&g_stats, 0, sizeof(g_stats));
|
||||||
|
|
||||||
for (int i = 0; i < COUNTOF(g_materials.rendermode); ++i)
|
g_materials.count = 1;
|
||||||
g_materials.rendermode[i].count = 0;
|
|
||||||
|
|
||||||
k_default_material.tex_metalness = tglob.blackTexture;
|
memset(g_materials.tex_to_mat, 0, sizeof g_materials.tex_to_mat);
|
||||||
|
|
||||||
|
for (int i = 0; i < COUNTOF(g_materials.for_rendermode); ++i)
|
||||||
|
g_materials.for_rendermode[i].count = 0;
|
||||||
|
|
||||||
|
// TODO make these texture constants static constants
|
||||||
|
k_default_material.tex_metalness = tglob.whiteTexture;
|
||||||
k_default_material.tex_roughness = tglob.whiteTexture;
|
k_default_material.tex_roughness = tglob.whiteTexture;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_TEXTURES; ++i) {
|
// TODO name?
|
||||||
r_vk_material_t *const mat = g_materials.materials + i;
|
g_materials.table[0].material = k_default_material;
|
||||||
const vk_texture_t *const tex = findTexture( i );
|
g_materials.table[0].material.tex_base_color = 0;
|
||||||
*mat = k_default_material;
|
|
||||||
|
|
||||||
if (tex)
|
|
||||||
mat->tex_base_color = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMaterialsFromFile( "pbr/materials.mat", MAX_INCLUDE_DEPTH );
|
loadMaterialsFromFile( "pbr/materials.mat", MAX_INCLUDE_DEPTH );
|
||||||
|
|
||||||
|
// Load materials by WAD files
|
||||||
{
|
{
|
||||||
for(const char *wad = g_map_entities.wadlist; *wad;) {
|
for(const char *wad = g_map_entities.wadlist; *wad;) {
|
||||||
const char *wad_end = wad;
|
const char *wad_end = wad;
|
||||||
|
@ -307,6 +426,7 @@ void R_VkMaterialsReload( void ) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load materials by map/BSP file
|
||||||
{
|
{
|
||||||
const model_t *map = gEngine.pfnGetModelByIndex( 1 );
|
const model_t *map = gEngine.pfnGetModelByIndex( 1 );
|
||||||
const char *filename = COM_FileWithoutPath(map->name);
|
const char *filename = COM_FileWithoutPath(map->name);
|
||||||
|
@ -334,31 +454,67 @@ void R_VkMaterialsLoadForModel( const struct model_s* mod ) {
|
||||||
if (mod->type == mod_brush)
|
if (mod->type == mod_brush)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// TODO add stats
|
||||||
|
|
||||||
const char *filename = COM_FileWithoutPath(mod->name);
|
const char *filename = COM_FileWithoutPath(mod->name);
|
||||||
const int no_ext_len = findFilenameExtension(filename, -1);
|
const int no_ext_len = findFilenameExtension(filename, -1);
|
||||||
loadMaterialsFromFileF("pbr/%s/%.*s.mat", mod->name, no_ext_len, filename);
|
loadMaterialsFromFileF("pbr/%s/%.*s.mat", mod->name, no_ext_len, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
r_vk_material_t R_VkMaterialGetForTexture( int tex_index ) {
|
r_vk_material_t R_VkMaterialGetForTexture( int tex_index ) {
|
||||||
|
//DEBUG("Getting material for tex_id=%d", tex_index);
|
||||||
ASSERT(tex_index >= 0);
|
ASSERT(tex_index >= 0);
|
||||||
ASSERT(tex_index < MAX_TEXTURES);
|
ASSERT(tex_index < MAX_TEXTURES);
|
||||||
|
|
||||||
return g_materials.materials[tex_index];
|
texture_to_material_t* const t2m = g_materials.tex_to_mat + tex_index;
|
||||||
|
|
||||||
|
if (t2m->mat_id > 0) {
|
||||||
|
ASSERT(t2m->mat_id < g_materials.count);
|
||||||
|
//DEBUG("Getting material for tex_id=%d", tex_index);
|
||||||
|
//printMaterial(t2m->mat_id);
|
||||||
|
return g_materials.table[t2m->mat_id].material;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t2m->mat_id == kMaterialNotChecked) {
|
||||||
|
// TODO check for replacement textures named in a predictable way
|
||||||
|
// If there are, create a new material and assign it here
|
||||||
|
|
||||||
|
const char* texname = findTexture(tex_index)->name;
|
||||||
|
DEBUG("Would try to load texture files by default names of \"%s\"", texname);
|
||||||
|
|
||||||
|
// If no PBR textures found, continue using legacy+default ones
|
||||||
|
t2m->mat_id = kMaterialNoReplacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
r_vk_material_t ret = k_default_material;
|
||||||
|
ret.tex_base_color = tex_index;
|
||||||
|
//DEBUG("Returning default material with tex_base_color=%d", tex_index);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
r_vk_material_ref_t R_VkMaterialGetForName( const char *name ) {
|
r_vk_material_ref_t R_VkMaterialGetForName( const char *name ) {
|
||||||
// TODO separate material table
|
// FIXME proper hash table here, don't depend on textures
|
||||||
// For now it depends on 1-to-1 mapping between materials and textures
|
const int dummy_tex_id_fixme = VK_FindTexture(name);
|
||||||
return (r_vk_material_ref_t){.index = VK_FindTexture(name)};
|
if (dummy_tex_id_fixme == 0) {
|
||||||
|
ERR("Material with name \"%s\" not found", name);
|
||||||
|
return (r_vk_material_ref_t){.index = -1,};
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(dummy_tex_id_fixme >= 0);
|
||||||
|
ASSERT(dummy_tex_id_fixme < MAX_TEXTURES);
|
||||||
|
|
||||||
|
return (r_vk_material_ref_t){.index = g_materials.tex_to_mat[dummy_tex_id_fixme].mat_id};
|
||||||
}
|
}
|
||||||
|
|
||||||
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref ) {
|
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref ) {
|
||||||
// TODO separate material table
|
if (ref.index < 0) {
|
||||||
// For now it depends on 1-to-1 mapping between materials and textures
|
r_vk_material_t ret = k_default_material;
|
||||||
ASSERT(ref.index >= 0);
|
ret.tex_base_color = 0; // Default/error texture
|
||||||
ASSERT(ref.index < MAX_TEXTURES);
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return g_materials.materials[ref.index];
|
ASSERT(ref.index < g_materials.count);
|
||||||
|
return g_materials.table[ref.index].material;
|
||||||
}
|
}
|
||||||
|
|
||||||
qboolean R_VkMaterialGetEx( int tex_id, int rendermode, r_vk_material_t *out_material ) {
|
qboolean R_VkMaterialGetEx( int tex_id, int rendermode, r_vk_material_t *out_material ) {
|
||||||
|
@ -370,11 +526,15 @@ qboolean R_VkMaterialGetEx( int tex_id, int rendermode, r_vk_material_t *out_mat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(rendermode < COUNTOF(g_materials.rendermode));
|
// TODO move rendermode-specifit things to by-texid-chains
|
||||||
const r_vk_material_per_mode_t* const mode = &g_materials.rendermode[rendermode];
|
ASSERT(rendermode < COUNTOF(g_materials.for_rendermode));
|
||||||
|
const r_vk_material_per_mode_t* const mode = &g_materials.for_rendermode[rendermode];
|
||||||
for (int i = 0; i < mode->count; ++i) {
|
for (int i = 0; i < mode->count; ++i) {
|
||||||
if (mode->materials[i].tex_id == tex_id) {
|
if (mode->map[i].tex_id == tex_id) {
|
||||||
*out_material = mode->materials[i].mat;
|
const int index = mode->map[i].mat.index;
|
||||||
|
ASSERT(index >= 0);
|
||||||
|
ASSERT(index < g_materials.count);
|
||||||
|
*out_material = g_materials.table[index].material;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,20 @@
|
||||||
|
|
||||||
#include "xash3d_types.h"
|
#include "xash3d_types.h"
|
||||||
|
|
||||||
|
/* TODO
|
||||||
|
#define MATERIAL_FIELDS_LIST(X) \
|
||||||
|
X(0, int, tex_base_color, basecolor_map, readTexture) \
|
||||||
|
X(1, int, tex_roughness, normal_map, readTexture) \
|
||||||
|
X(2, int, tex_metalness, metal_map, readTexture) \
|
||||||
|
X(3, int, tex_normalmap, roughness_map, readTexture) \
|
||||||
|
X(4, vec4_t, base_color, base_color, readVec4) \
|
||||||
|
X(5, float, roughness, roughness, readFloat) \
|
||||||
|
X(6, float, metalness, metalness, readFloat) \
|
||||||
|
X(7, float, normal_scale, normal_scale, readFloat) \
|
||||||
|
X(7, int, rendermode, rendermode, readRendermode) \
|
||||||
|
X(8, int, _inherit, inherit, readInerit) \
|
||||||
|
*/
|
||||||
|
|
||||||
typedef struct r_vk_material_s {
|
typedef struct r_vk_material_s {
|
||||||
int tex_base_color;
|
int tex_base_color;
|
||||||
int tex_roughness;
|
int tex_roughness;
|
||||||
|
@ -26,9 +40,10 @@ void R_VkMaterialsReload( void );
|
||||||
struct model_s;
|
struct model_s;
|
||||||
void R_VkMaterialsLoadForModel( const struct model_s* mod );
|
void R_VkMaterialsLoadForModel( const struct model_s* mod );
|
||||||
|
|
||||||
r_vk_material_t R_VkMaterialGetForTexture( int tex_id );
|
|
||||||
|
|
||||||
qboolean R_VkMaterialGetEx( int tex_id, int rendermode, r_vk_material_t *out_material );
|
|
||||||
|
|
||||||
r_vk_material_ref_t R_VkMaterialGetForName( const char *name );
|
r_vk_material_ref_t R_VkMaterialGetForName( const char *name );
|
||||||
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref );
|
r_vk_material_t R_VkMaterialGetForRef( r_vk_material_ref_t ref );
|
||||||
|
|
||||||
|
r_vk_material_t R_VkMaterialGetForTexture( int tex_id );
|
||||||
|
r_vk_material_t R_VkMaterialGetForTextureChrome( int tex_id );
|
||||||
|
|
||||||
|
qboolean R_VkMaterialGetEx( int tex_id, int rendermode, r_vk_material_t *out_material );
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "vk_common.h"
|
#include "vk_common.h"
|
||||||
#include "vk_logs.h"
|
#include "vk_logs.h"
|
||||||
|
|
||||||
|
#include "profiler.h"
|
||||||
|
|
||||||
#define LOG_MODULE LogModule_Meatpipe
|
#define LOG_MODULE LogModule_Meatpipe
|
||||||
|
|
||||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||||
|
@ -427,6 +429,7 @@ void R_VkMeatpipeDestroy(vk_meatpipe_t *mp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void R_VkMeatpipePerform(vk_meatpipe_t *mp, struct vk_combuf_s *combuf, vk_meatpipe_perfrom_args_t args) {
|
void R_VkMeatpipePerform(vk_meatpipe_t *mp, struct vk_combuf_s *combuf, vk_meatpipe_perfrom_args_t args) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(perform, __FUNCTION__);
|
||||||
for (int i = 0; i < mp->passes_count; ++i) {
|
for (int i = 0; i < mp->passes_count; ++i) {
|
||||||
const vk_meatpipe_pass_t *pass = mp->passes + i;
|
const vk_meatpipe_pass_t *pass = mp->passes + i;
|
||||||
RayPassPerform(pass->pass, combuf,
|
RayPassPerform(pass->pass, combuf,
|
||||||
|
@ -439,4 +442,5 @@ void R_VkMeatpipePerform(vk_meatpipe_t *mp, struct vk_combuf_s *combuf, vk_meatp
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
APROF_SCOPE_END(perform);
|
||||||
}
|
}
|
||||||
|
|
|
@ -266,10 +266,10 @@ static void drawOverlay( VkCommandBuffer cmdbuf ) {
|
||||||
{
|
{
|
||||||
vk_texture_t *texture = findTexture(g2d.batch[i].texture);
|
vk_texture_t *texture = findTexture(g2d.batch[i].texture);
|
||||||
const VkPipeline pipeline = g2d.pipelines[g2d.batch[i].blending_mode];
|
const VkPipeline pipeline = g2d.pipelines[g2d.batch[i].blending_mode];
|
||||||
if (texture->vk.descriptor)
|
if (texture->vk.descriptor_unorm)
|
||||||
{
|
{
|
||||||
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
vkCmdBindPipeline(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g2d.pipeline_layout, 0, 1, &texture->vk.descriptor, 0, NULL);
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g2d.pipeline_layout, 0, 1, &texture->vk.descriptor_unorm, 0, NULL);
|
||||||
vkCmdDraw(cmdbuf, g2d.batch[i].vertex_count, 1, g2d.batch[i].vertex_offset, 0);
|
vkCmdDraw(cmdbuf, g2d.batch[i].vertex_count, 1, g2d.batch[i].vertex_offset, 0);
|
||||||
} // FIXME else what?
|
} // FIXME else what?
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "vk_render.h"
|
#include "vk_render.h"
|
||||||
#include "vk_logs.h"
|
#include "vk_logs.h"
|
||||||
|
|
||||||
|
#include "profiler.h"
|
||||||
|
|
||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
|
|
||||||
#define LOG_MODULE LogModule_RT
|
#define LOG_MODULE LogModule_RT
|
||||||
|
@ -240,6 +242,7 @@ static void createTlas( vk_combuf_t *combuf, VkDeviceAddress instances_addr ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
|
vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(prepare, __FUNCTION__);
|
||||||
ASSERT(g_ray_model_state.frame.instances_count > 0);
|
ASSERT(g_ray_model_state.frame.instances_count > 0);
|
||||||
DEBUG_BEGIN(combuf->cmdbuf, "prepare tlas");
|
DEBUG_BEGIN(combuf->cmdbuf, "prepare tlas");
|
||||||
|
|
||||||
|
@ -345,6 +348,7 @@ vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
|
||||||
0, 0, NULL, COUNTOF(bmb), bmb, 0, NULL);
|
0, 0, NULL, COUNTOF(bmb), bmb, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APROF_SCOPE_END(prepare);
|
||||||
return (vk_resource_t){
|
return (vk_resource_t){
|
||||||
.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
||||||
.value = (vk_descriptor_value_t){
|
.value = (vk_descriptor_value_t){
|
||||||
|
|
|
@ -298,6 +298,20 @@ rt_draw_instance_t *getDrawInstance(void) {
|
||||||
return g_ray_model_state.frame.instances + (g_ray_model_state.frame.instances_count++);
|
return g_ray_model_state.frame.instances + (g_ray_model_state.frame.instances_count++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float sRGBtoLinearScalar(const float sRGB) {
|
||||||
|
// IEC 61966-2-1:1999
|
||||||
|
const float linearLow = sRGB / 12.92f;
|
||||||
|
const float linearHigh = powf((sRGB + 0.055f) / 1.055f, 2.4f);
|
||||||
|
return sRGB <= 0.04045f ? linearLow : linearHigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sRGBtoLinearVec4(const vec4_t in, vec4_t out) {
|
||||||
|
out[0] = sRGBtoLinearScalar(in[0]);
|
||||||
|
out[1] = sRGBtoLinearScalar(in[1]);
|
||||||
|
out[2] = sRGBtoLinearScalar(in[2]);
|
||||||
|
out[3] = in[3];
|
||||||
|
}
|
||||||
|
|
||||||
void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
|
void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
|
||||||
if (!model || !model->blas)
|
if (!model || !model->blas)
|
||||||
return;
|
return;
|
||||||
|
@ -329,7 +343,7 @@ void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
|
||||||
draw_instance->blas_addr = model->blas_addr;
|
draw_instance->blas_addr = model->blas_addr;
|
||||||
draw_instance->kusochki_offset = kusochki_offset;
|
draw_instance->kusochki_offset = kusochki_offset;
|
||||||
draw_instance->material_mode = args.material_mode;
|
draw_instance->material_mode = args.material_mode;
|
||||||
Vector4Copy(*args.color, draw_instance->color);
|
sRGBtoLinearVec4(*args.color_srgb, draw_instance->color);
|
||||||
Matrix3x4_Copy(draw_instance->transform_row, args.transform);
|
Matrix3x4_Copy(draw_instance->transform_row, args.transform);
|
||||||
Matrix4x4_Copy(draw_instance->prev_transform_row, args.prev_transform);
|
Matrix4x4_Copy(draw_instance->prev_transform_row, args.prev_transform);
|
||||||
}
|
}
|
||||||
|
@ -390,6 +404,7 @@ void RT_DynamicModelShutdown(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RT_DynamicModelProcessFrame(void) {
|
void RT_DynamicModelProcessFrame(void) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(process, __FUNCTION__);
|
||||||
for (int i = 0; i < MATERIAL_MODE_COUNT; ++i) {
|
for (int i = 0; i < MATERIAL_MODE_COUNT; ++i) {
|
||||||
rt_dynamic_t *const dyn = g_dyn.groups + i;
|
rt_dynamic_t *const dyn = g_dyn.groups + i;
|
||||||
if (!dyn->geometries_count)
|
if (!dyn->geometries_count)
|
||||||
|
@ -427,6 +442,7 @@ void RT_DynamicModelProcessFrame(void) {
|
||||||
tail:
|
tail:
|
||||||
dyn->geometries_count = 0;
|
dyn->geometries_count = 0;
|
||||||
}
|
}
|
||||||
|
APROF_SCOPE_END(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RT_FrameAddOnce( rt_frame_add_once_t args ) {
|
void RT_FrameAddOnce( rt_frame_add_once_t args ) {
|
||||||
|
|
|
@ -589,14 +589,14 @@ void VK_RenderEnd( VkCommandBuffer cmdbuf, qboolean draw )
|
||||||
|
|
||||||
if (lightmap != draw->draw.lightmap) {
|
if (lightmap != draw->draw.lightmap) {
|
||||||
lightmap = draw->draw.lightmap;
|
lightmap = draw->draw.lightmap;
|
||||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 2, 1, &findTexture(lightmap)->vk.descriptor, 0, NULL);
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 2, 1, &findTexture(lightmap)->vk.descriptor_unorm, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture != draw->draw.texture)
|
if (texture != draw->draw.texture)
|
||||||
{
|
{
|
||||||
texture = draw->draw.texture;
|
texture = draw->draw.texture;
|
||||||
// TODO names/enums for binding points
|
// TODO names/enums for binding points
|
||||||
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 1, 1, &findTexture(texture)->vk.descriptor, 0, NULL);
|
vkCmdBindDescriptorSets(cmdbuf, VK_PIPELINE_BIND_POINT_GRAPHICS, g_render.pipeline_layout, 1, 1, &findTexture(texture)->vk.descriptor_unorm, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only indexed mode is supported
|
// Only indexed mode is supported
|
||||||
|
@ -784,7 +784,7 @@ void R_RenderModelDraw(const vk_render_model_t *model, r_model_draw_t args) {
|
||||||
.material_mode = args.material_mode,
|
.material_mode = args.material_mode,
|
||||||
.transform = (const matrix3x4*)args.transform,
|
.transform = (const matrix3x4*)args.transform,
|
||||||
.prev_transform = (const matrix3x4*)args.prev_transform,
|
.prev_transform = (const matrix3x4*)args.prev_transform,
|
||||||
.color = args.color,
|
.color_srgb = args.color,
|
||||||
.dynamic_polylights = model->dynamic_polylights,
|
.dynamic_polylights = model->dynamic_polylights,
|
||||||
.dynamic_polylights_count = model->dynamic_polylights_count,
|
.dynamic_polylights_count = model->dynamic_polylights_count,
|
||||||
.override = {
|
.override = {
|
||||||
|
|
|
@ -543,7 +543,7 @@ static const ref_interface_t gReffuncs =
|
||||||
VK_FindTexture,
|
VK_FindTexture,
|
||||||
VK_TextureName,
|
VK_TextureName,
|
||||||
VK_TextureData,
|
VK_TextureData,
|
||||||
VK_LoadTexture,
|
VK_LoadTextureExternal,
|
||||||
VK_CreateTexture,
|
VK_CreateTexture,
|
||||||
VK_LoadTextureArray,
|
VK_LoadTextureArray,
|
||||||
VK_CreateTextureArray,
|
VK_CreateTextureArray,
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "vk_logs.h"
|
#include "vk_logs.h"
|
||||||
|
|
||||||
#include "alolcator.h"
|
#include "alolcator.h"
|
||||||
|
#include "profiler.h"
|
||||||
|
|
||||||
#include "eiface.h"
|
#include "eiface.h"
|
||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
|
@ -67,7 +67,7 @@ enum {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char name[64];
|
char name[64];
|
||||||
vk_resource_t resource;
|
vk_resource_t resource;
|
||||||
xvk_image_t image;
|
r_vk_image_t image;
|
||||||
int refcount;
|
int refcount;
|
||||||
int source_index_plus_1;
|
int source_index_plus_1;
|
||||||
} rt_resource_t;
|
} rt_resource_t;
|
||||||
|
@ -172,6 +172,7 @@ typedef struct {
|
||||||
} perform_tracing_args_t;
|
} perform_tracing_args_t;
|
||||||
|
|
||||||
static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* args) {
|
static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* args) {
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(perform, __FUNCTION__);
|
||||||
const VkCommandBuffer cmdbuf = combuf->cmdbuf;
|
const VkCommandBuffer cmdbuf = combuf->cmdbuf;
|
||||||
|
|
||||||
#define RES_SET_BUFFER(name, type_, source_, offset_, size_) \
|
#define RES_SET_BUFFER(name, type_, source_, offset_, size_) \
|
||||||
|
@ -240,7 +241,7 @@ static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* a
|
||||||
|
|
||||||
// Swap resources
|
// Swap resources
|
||||||
const vk_resource_t tmp_res = res->resource;
|
const vk_resource_t tmp_res = res->resource;
|
||||||
const xvk_image_t tmp_img = res->image;
|
const r_vk_image_t tmp_img = res->image;
|
||||||
|
|
||||||
res->resource = src->resource;
|
res->resource = src->resource;
|
||||||
res->image = src->image;
|
res->image = src->image;
|
||||||
|
@ -340,6 +341,8 @@ static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* a
|
||||||
g_rtx.mainpipe_out->resource.write.image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
g_rtx.mainpipe_out->resource.write.image_layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||||
}
|
}
|
||||||
DEBUG_END(cmdbuf);
|
DEBUG_END(cmdbuf);
|
||||||
|
|
||||||
|
APROF_SCOPE_END(perform);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cleanupResources(void) {
|
static void cleanupResources(void) {
|
||||||
|
@ -348,7 +351,7 @@ static void cleanupResources(void) {
|
||||||
if (!res->name[0] || res->refcount || !res->image.image)
|
if (!res->name[0] || res->refcount || !res->image.image)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
XVK_ImageDestroy(&res->image);
|
R_VkImageDestroy(&res->image);
|
||||||
res->name[0] = '\0';
|
res->name[0] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,10 +392,11 @@ static void reloadMainpipe(void) {
|
||||||
|
|
||||||
for (int i = 0; i < newpipe->resources_count; ++i) {
|
for (int i = 0; i < newpipe->resources_count; ++i) {
|
||||||
const vk_meatpipe_resource_t *mr = newpipe->resources + i;
|
const vk_meatpipe_resource_t *mr = newpipe->resources + i;
|
||||||
DEBUG("res %d/%d: %s descriptor=%u count=%d flags=[%c%c] image_format=%u",
|
DEBUG("res %d/%d: %s descriptor=%u count=%d flags=[%c%c] image_format=(%s)%u",
|
||||||
i, newpipe->resources_count, mr->name, mr->descriptor_type, mr->count,
|
i, newpipe->resources_count, mr->name, mr->descriptor_type, mr->count,
|
||||||
(mr->flags & MEATPIPE_RES_WRITE) ? 'W' : ' ',
|
(mr->flags & MEATPIPE_RES_WRITE) ? 'W' : ' ',
|
||||||
(mr->flags & MEATPIPE_RES_CREATE) ? 'C' : ' ',
|
(mr->flags & MEATPIPE_RES_CREATE) ? 'C' : ' ',
|
||||||
|
R_VkFormatName(mr->image_format),
|
||||||
mr->image_format);
|
mr->image_format);
|
||||||
|
|
||||||
const qboolean create = !!(mr->flags & MEATPIPE_RES_CREATE);
|
const qboolean create = !!(mr->flags & MEATPIPE_RES_CREATE);
|
||||||
|
@ -417,8 +421,11 @@ static void reloadMainpipe(void) {
|
||||||
newpipe_out = res;
|
newpipe_out = res;
|
||||||
|
|
||||||
if (create) {
|
if (create) {
|
||||||
if (res->image.image == VK_NULL_HANDLE) {
|
if (res->image.image == VK_NULL_HANDLE || mr->image_format != res->image.format) {
|
||||||
const xvk_image_create_t create = {
|
if (res->image.image != VK_NULL_HANDLE) {
|
||||||
|
R_VkImageDestroy(&res->image);
|
||||||
|
}
|
||||||
|
const r_vk_image_create_t create = {
|
||||||
.debug_name = mr->name,
|
.debug_name = mr->name,
|
||||||
.width = FRAME_WIDTH,
|
.width = FRAME_WIDTH,
|
||||||
.height = FRAME_HEIGHT,
|
.height = FRAME_HEIGHT,
|
||||||
|
@ -429,13 +436,10 @@ static void reloadMainpipe(void) {
|
||||||
// TODO figure out how to detect this need properly. prev_dest is not defined as "output"
|
// TODO figure out how to detect this need properly. prev_dest is not defined as "output"
|
||||||
//.usage = VK_IMAGE_USAGE_STORAGE_BIT | (output ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0),
|
//.usage = VK_IMAGE_USAGE_STORAGE_BIT | (output ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT : 0),
|
||||||
.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
.has_alpha = true,
|
.flags = kVkImageFlagHasAlpha,
|
||||||
.is_cubemap = false,
|
|
||||||
};
|
};
|
||||||
res->image = XVK_ImageCreate(&create);
|
res->image = R_VkImageCreate(&create);
|
||||||
Q_strncpy(res->name, mr->name, sizeof(res->name));
|
Q_strncpy(res->name, mr->name, sizeof(res->name));
|
||||||
} else {
|
|
||||||
// TODO if (mr->image_format != res->image.format) { S_ERROR and goto fail }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +499,7 @@ static void reloadMainpipe(void) {
|
||||||
|
|
||||||
// TODO currently changing texture format is not handled. It will try to reuse existing image with the old format
|
// TODO currently changing texture format is not handled. It will try to reuse existing image with the old format
|
||||||
// which will probably fail. To handle it we'd need to refactor this:
|
// which will probably fail. To handle it we'd need to refactor this:
|
||||||
// 1. xvk_image_t should have a field with its current format? (or we'd also store if with the resource here)
|
// 1. r_vk_image_t should have a field with its current format? (or we'd also store if with the resource here)
|
||||||
// 2. do another loop here to detect format mismatch and recreate.
|
// 2. do another loop here to detect format mismatch and recreate.
|
||||||
|
|
||||||
g_rtx.mainpipe = newpipe;
|
g_rtx.mainpipe = newpipe;
|
||||||
|
@ -515,6 +519,8 @@ fail:
|
||||||
|
|
||||||
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
||||||
{
|
{
|
||||||
|
APROF_SCOPE_DECLARE_BEGIN(ray_frame_end, __FUNCTION__);
|
||||||
|
|
||||||
const VkCommandBuffer cmdbuf = args->combuf->cmdbuf;
|
const VkCommandBuffer cmdbuf = args->combuf->cmdbuf;
|
||||||
// const xvk_ray_frame_images_t* current_frame = g_rtx.frames + (g_rtx.frame_number % 2);
|
// const xvk_ray_frame_images_t* current_frame = g_rtx.frames + (g_rtx.frame_number % 2);
|
||||||
|
|
||||||
|
@ -579,6 +585,8 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
||||||
};
|
};
|
||||||
performTracing( args->combuf, &trace_args );
|
performTracing( args->combuf, &trace_args );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
APROF_SCOPE_END(ray_frame_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reloadPipeline( void ) {
|
static void reloadPipeline( void ) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ qboolean RT_ModelUpdateMaterials(struct rt_model_s *model, const struct vk_rende
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int material_mode;
|
int material_mode;
|
||||||
const matrix3x4 *transform, *prev_transform;
|
const matrix3x4 *transform, *prev_transform;
|
||||||
const vec4_t *color;
|
const vec4_t *color_srgb;
|
||||||
|
|
||||||
struct rt_light_add_polygon_s *dynamic_polylights;
|
struct rt_light_add_polygon_s *dynamic_polylights;
|
||||||
int dynamic_polylights_count;
|
int dynamic_polylights_count;
|
||||||
|
|
|
@ -230,6 +230,9 @@ int R_FIXME_GetEntityRenderMode( cl_entity_t *ent )
|
||||||
}
|
}
|
||||||
|
|
||||||
void R_SceneMapDestroy( void ) {
|
void R_SceneMapDestroy( void ) {
|
||||||
|
// Make sure no rendering is happening
|
||||||
|
XVK_CHECK(vkDeviceWaitIdle( vk_core.device ));
|
||||||
|
|
||||||
VK_BrushModelDestroyAll();
|
VK_BrushModelDestroyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -242,12 +242,12 @@ static const dframetype_t *VK_SpriteLoadFrame( model_t *mod, const void *pin, ms
|
||||||
if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite
|
if( FBitSet( mod->flags, MODEL_CLIENT )) // it's a HUD sprite
|
||||||
{
|
{
|
||||||
Q_snprintf( texname, sizeof( texname ), "#HUD/%s(%s:%i%i).spr", ctx->sprite_name, ctx->group_suffix, num / 10, num % 10 );
|
Q_snprintf( texname, sizeof( texname ), "#HUD/%s(%s:%i%i).spr", ctx->sprite_name, ctx->group_suffix, num / 10, num % 10 );
|
||||||
gl_texturenum = VK_LoadTexture( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
|
gl_texturenum = VK_LoadTextureExternal( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Q_snprintf( texname, sizeof( texname ), "#%s(%s:%i%i).spr", ctx->sprite_name, ctx->group_suffix, num / 10, num % 10 );
|
Q_snprintf( texname, sizeof( texname ), "#%s(%s:%i%i).spr", ctx->sprite_name, ctx->group_suffix, num / 10, num % 10 );
|
||||||
gl_texturenum = VK_LoadTexture( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
|
gl_texturenum = VK_LoadTextureExternal( texname, pin, pinframe.width * pinframe.height * bytes, ctx->r_texFlags );
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup frame description
|
// setup frame description
|
||||||
|
|
|
@ -3337,7 +3337,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
|
||||||
|
|
||||||
// build the texname
|
// build the texname
|
||||||
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );
|
Q_snprintf( texname, sizeof( texname ), "#%s/%s.mdl", mdlname, name );
|
||||||
ptexture->index = VK_LoadTexture( texname, (byte *)ptexture, size, flags );
|
ptexture->index = VK_LoadTextureExternal( texname, (byte *)ptexture, size, flags );
|
||||||
|
|
||||||
if( !ptexture->index )
|
if( !ptexture->index )
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,7 @@ static struct {
|
||||||
VkImageView *image_views;
|
VkImageView *image_views;
|
||||||
VkFramebuffer *framebuffers;
|
VkFramebuffer *framebuffers;
|
||||||
|
|
||||||
xvk_image_t depth;
|
r_vk_image_t depth;
|
||||||
|
|
||||||
uint32_t width, height;
|
uint32_t width, height;
|
||||||
|
|
||||||
|
@ -33,11 +33,10 @@ static uint32_t clamp_u32(uint32_t v, uint32_t min, uint32_t max) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createDepthImage(int w, int h, VkFormat depth_format) {
|
static void createDepthImage(int w, int h, VkFormat depth_format) {
|
||||||
const xvk_image_create_t xic = {
|
const r_vk_image_create_t xic = {
|
||||||
.debug_name = "depth",
|
.debug_name = "depth",
|
||||||
.format = depth_format,
|
.format = depth_format,
|
||||||
.has_alpha = false,
|
.flags = 0,
|
||||||
.is_cubemap = false,
|
|
||||||
.mips = 1,
|
.mips = 1,
|
||||||
.layers = 1,
|
.layers = 1,
|
||||||
.width = w,
|
.width = w,
|
||||||
|
@ -45,7 +44,7 @@ static void createDepthImage(int w, int h, VkFormat depth_format) {
|
||||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||||
};
|
};
|
||||||
g_swapchain.depth = XVK_ImageCreate( &xic );
|
g_swapchain.depth = R_VkImageCreate( &xic );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroySwapchainAndFramebuffers( VkSwapchainKHR swapchain ) {
|
static void destroySwapchainAndFramebuffers( VkSwapchainKHR swapchain ) {
|
||||||
|
@ -56,7 +55,7 @@ static void destroySwapchainAndFramebuffers( VkSwapchainKHR swapchain ) {
|
||||||
vkDestroyFramebuffer(vk_core.device, g_swapchain.framebuffers[i], NULL);
|
vkDestroyFramebuffer(vk_core.device, g_swapchain.framebuffers[i], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
XVK_ImageDestroy( &g_swapchain.depth );
|
R_VkImageDestroy( &g_swapchain.depth );
|
||||||
|
|
||||||
vkDestroySwapchainKHR(vk_core.device, swapchain, NULL);
|
vkDestroySwapchainKHR(vk_core.device, swapchain, NULL);
|
||||||
}
|
}
|
||||||
|
@ -187,7 +186,12 @@ qboolean R_VkSwapchainInit( VkRenderPass render_pass, VkFormat depth_format ) {
|
||||||
VkSurfaceCapabilitiesKHR surface_caps;
|
VkSurfaceCapabilitiesKHR surface_caps;
|
||||||
XVK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_core.physical_device.device, vk_core.surface.surface, &surface_caps));
|
XVK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vk_core.physical_device.device, vk_core.surface.surface, &surface_caps));
|
||||||
|
|
||||||
g_swapchain.image_format = VK_FORMAT_B8G8R8A8_UNORM;//SRGB, // TODO get from surface_formats
|
/*
|
||||||
|
[2023:10:09|13:03:52] Error: Validation: Validation Error: [ VUID-VkSwapchainCreateInfoKHR-imageFormat-01778 ] Object 0: handle = 0x555556af6a00, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xc036022f | vkCreateSwapchainKHR(): pCreateInfo->imageFormat VK_FORMAT_B8G8R8A8_SRGB with tiling VK_IMAGE_TILING_OPTIMAL does not support usage that includes VK_IMAGE_USAGE_STORAGE_BIT. The Vulkan spec states: The implied image creation parameters of the swapchain must be supported as reported by vkGetPhysicalDeviceImageFormatProperties (https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-imageFormat-01778)
|
||||||
|
*/
|
||||||
|
//g_swapchain.image_format = VK_FORMAT_B8G8R8A8_SRGB;
|
||||||
|
|
||||||
|
g_swapchain.image_format = VK_FORMAT_B8G8R8A8_UNORM; // TODO get from surface_formats
|
||||||
g_swapchain.render_pass = render_pass;
|
g_swapchain.render_pass = render_pass;
|
||||||
g_swapchain.depth_format = depth_format;
|
g_swapchain.depth_format = depth_format;
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "vk_mapents.h" // wadlist
|
#include "vk_mapents.h" // wadlist
|
||||||
#include "vk_combuf.h"
|
#include "vk_combuf.h"
|
||||||
#include "vk_logs.h"
|
#include "vk_logs.h"
|
||||||
|
#include "r_speeds.h"
|
||||||
|
|
||||||
#include "xash3d_mathlib.h"
|
#include "xash3d_mathlib.h"
|
||||||
#include "crtlib.h"
|
#include "crtlib.h"
|
||||||
|
@ -22,18 +23,29 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#define LOG_MODULE LogModule_Textures
|
#define LOG_MODULE LogModule_Textures
|
||||||
|
#define MODULE_NAME "textures"
|
||||||
|
|
||||||
#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2)
|
#define TEXTURES_HASH_SIZE (MAX_TEXTURES >> 2)
|
||||||
|
|
||||||
static vk_texture_t vk_textures[MAX_TEXTURES];
|
static vk_texture_t vk_textures[MAX_TEXTURES];
|
||||||
static vk_texture_t* vk_texturesHashTable[TEXTURES_HASH_SIZE];
|
static vk_texture_t* vk_texturesHashTable[TEXTURES_HASH_SIZE];
|
||||||
static uint vk_numTextures;
|
static uint vk_numTextures;
|
||||||
vk_textures_global_t tglob = {0};
|
vk_textures_global_t tglob = {0};
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct {
|
||||||
|
int count;
|
||||||
|
int size_total;
|
||||||
|
} stats;
|
||||||
|
} g_textures;
|
||||||
|
|
||||||
static void VK_CreateInternalTextures(void);
|
static void VK_CreateInternalTextures(void);
|
||||||
static VkSampler pickSamplerForFlags( texFlags_t flags );
|
static VkSampler pickSamplerForFlags( texFlags_t flags );
|
||||||
|
|
||||||
void initTextures( void ) {
|
void initTextures( void ) {
|
||||||
|
R_SPEEDS_METRIC(g_textures.stats.count, "count", kSpeedsMetricCount);
|
||||||
|
R_SPEEDS_METRIC(g_textures.stats.size_total, "size_total", kSpeedsMetricBytes);
|
||||||
|
|
||||||
memset( vk_textures, 0, sizeof( vk_textures ));
|
memset( vk_textures, 0, sizeof( vk_textures ));
|
||||||
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
|
memset( vk_texturesHashTable, 0, sizeof( vk_texturesHashTable ));
|
||||||
vk_numTextures = 0;
|
vk_numTextures = 0;
|
||||||
|
@ -86,7 +98,9 @@ void destroyTextures( void )
|
||||||
|
|
||||||
unloadSkybox();
|
unloadSkybox();
|
||||||
|
|
||||||
XVK_ImageDestroy(&tglob.cubemap_placeholder.vk.image);
|
R_VkImageDestroy(&tglob.cubemap_placeholder.vk.image);
|
||||||
|
g_textures.stats.size_total -= tglob.cubemap_placeholder.total_size;
|
||||||
|
g_textures.stats.count--;
|
||||||
memset(&tglob.cubemap_placeholder, 0, sizeof(tglob.cubemap_placeholder));
|
memset(&tglob.cubemap_placeholder, 0, sizeof(tglob.cubemap_placeholder));
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYSIZE(tglob.samplers); ++i) {
|
for (int i = 0; i < ARRAYSIZE(tglob.samplers); ++i) {
|
||||||
|
@ -263,9 +277,11 @@ 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 qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap, colorspace_hint_e colorspace_hint);
|
||||||
|
|
||||||
static int VK_LoadTextureF(int flags, const char *fmt, ...) {
|
static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint );
|
||||||
|
|
||||||
|
static int VK_LoadTextureF(int flags, colorspace_hint_e colorspace, const char *fmt, ...) {
|
||||||
int tex_id = 0;
|
int tex_id = 0;
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
va_list argptr;
|
va_list argptr;
|
||||||
|
@ -273,7 +289,7 @@ static int VK_LoadTextureF(int flags, const char *fmt, ...) {
|
||||||
vsnprintf( buffer, sizeof buffer, fmt, argptr );
|
vsnprintf( buffer, sizeof buffer, fmt, argptr );
|
||||||
va_end( argptr );
|
va_end( argptr );
|
||||||
|
|
||||||
return VK_LoadTexture(buffer, NULL, 0, flags);
|
return loadTextureInternal(buffer, NULL, 0, flags, colorspace);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BLUE_NOISE_NAME_F "bluenoise/LDR_RGBA_%d.png"
|
#define BLUE_NOISE_NAME_F "bluenoise/LDR_RGBA_%d.png"
|
||||||
|
@ -322,7 +338,7 @@ static qboolean generateFallbackNoiseTextures(void) {
|
||||||
static qboolean loadBlueNoiseTextures(void) {
|
static qboolean loadBlueNoiseTextures(void) {
|
||||||
int blueNoiseTexturesBegin = -1;
|
int blueNoiseTexturesBegin = -1;
|
||||||
for (int i = 0; i < 64; ++i) {
|
for (int i = 0; i < 64; ++i) {
|
||||||
const int texid = VK_LoadTextureF(TF_NOMIPMAP, BLUE_NOISE_NAME_F, i);
|
const int texid = VK_LoadTextureF(TF_NOMIPMAP, kColorspaceLinear, BLUE_NOISE_NAME_F, i);
|
||||||
|
|
||||||
if (blueNoiseTexturesBegin == -1) {
|
if (blueNoiseTexturesBegin == -1) {
|
||||||
if (texid <= 0) {
|
if (texid <= 0) {
|
||||||
|
@ -417,16 +433,19 @@ static void VK_CreateInternalTextures( void )
|
||||||
sides[4] = pic;
|
sides[4] = pic;
|
||||||
sides[5] = pic;
|
sides[5] = pic;
|
||||||
|
|
||||||
uploadTexture( &tglob.cubemap_placeholder, sides, 6, true );
|
uploadTexture( &tglob.cubemap_placeholder, sides, 6, true, kColorspaceGamma );
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBlueNoiseTextures();
|
loadBlueNoiseTextures();
|
||||||
}
|
}
|
||||||
|
|
||||||
static VkFormat VK_GetFormat(pixformat_t format) {
|
static VkFormat VK_GetFormat(pixformat_t format, colorspace_hint_e colorspace_hint ) {
|
||||||
switch(format)
|
switch(format)
|
||||||
{
|
{
|
||||||
case PF_RGBA_32: return VK_FORMAT_R8G8B8A8_UNORM;
|
case PF_RGBA_32:
|
||||||
|
return (colorspace_hint == kColorspaceLinear)
|
||||||
|
? VK_FORMAT_R8G8B8A8_UNORM
|
||||||
|
: VK_FORMAT_R8G8B8A8_SRGB;
|
||||||
default:
|
default:
|
||||||
WARN("FIXME unsupported pixformat_t %d", format);
|
WARN("FIXME unsupported pixformat_t %d", format);
|
||||||
return VK_FORMAT_UNDEFINED;
|
return VK_FORMAT_UNDEFINED;
|
||||||
|
@ -619,10 +638,12 @@ static VkSampler pickSamplerForFlags( texFlags_t flags ) {
|
||||||
return tglob.default_sampler_fixme;
|
return tglob.default_sampler_fixme;
|
||||||
}
|
}
|
||||||
|
|
||||||
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap) {
|
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap, colorspace_hint_e colorspace_hint) {
|
||||||
const VkFormat format = VK_GetFormat(layers[0]->type);
|
const VkFormat format = VK_GetFormat(layers[0]->type, colorspace_hint);
|
||||||
int mipCount = 0;
|
int mipCount = 0;
|
||||||
|
|
||||||
|
tex->total_size = 0;
|
||||||
|
|
||||||
// TODO non-rbga textures
|
// TODO non-rbga textures
|
||||||
|
|
||||||
for (int i = 0; i < num_layers; ++i) {
|
for (int i = 0; i < num_layers; ++i) {
|
||||||
|
@ -658,7 +679,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||||
tex->height = layers[0]->height;
|
tex->height = layers[0]->height;
|
||||||
mipCount = CalcMipmapCount( tex, true);
|
mipCount = CalcMipmapCount( tex, true);
|
||||||
|
|
||||||
DEBUG("Uploading texture %s, mips=%d, layers=%d", tex->name, mipCount, num_layers);
|
DEBUG("Uploading texture[%d] %s, mips=%d, layers=%d", (int)(tex-vk_textures), 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
|
||||||
|
@ -670,7 +691,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||||
// data = GL_ApplyFilter( data, tex->width, tex->height );
|
// data = GL_ApplyFilter( data, tex->width, tex->height );
|
||||||
|
|
||||||
{
|
{
|
||||||
const xvk_image_create_t create = {
|
const r_vk_image_create_t create = {
|
||||||
.debug_name = tex->name,
|
.debug_name = tex->name,
|
||||||
.width = tex->width,
|
.width = tex->width,
|
||||||
.height = tex->height,
|
.height = tex->height,
|
||||||
|
@ -679,10 +700,12 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||||
.format = format,
|
.format = format,
|
||||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
.has_alpha = layers[0]->flags & IMAGE_HAS_ALPHA,
|
.flags = 0
|
||||||
.is_cubemap = cubemap,
|
| ((layers[0]->flags & IMAGE_HAS_ALPHA) ? kVkImageFlagHasAlpha : 0)
|
||||||
|
| (cubemap ? kVkImageFlagIsCubemap : 0)
|
||||||
|
| (colorspace_hint == kColorspaceGamma ? kVkImageFlagCreateUnormView : 0),
|
||||||
};
|
};
|
||||||
tex->vk.image = XVK_ImageCreate(&create);
|
tex->vk.image = R_VkImageCreate(&create);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -720,7 +743,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||||
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 );
|
||||||
const uint32_t texel_block_size = 4; // TODO compressed might be different
|
const uint32_t texel_block_size = R_VkImageFormatTexelBlockSize(format);
|
||||||
const vk_staging_image_args_t staging_args = {
|
const vk_staging_image_args_t staging_args = {
|
||||||
.image = tex->vk.image.image,
|
.image = tex->vk.image.image,
|
||||||
.region = (VkBufferImageCopy) {
|
.region = (VkBufferImageCopy) {
|
||||||
|
@ -748,6 +771,8 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||||
ASSERT(staging.ptr);
|
ASSERT(staging.ptr);
|
||||||
memcpy(staging.ptr, buf, mip_size);
|
memcpy(staging.ptr, buf, mip_size);
|
||||||
|
|
||||||
|
tex->total_size += mip_size;
|
||||||
|
|
||||||
// Build mip in place for the next mip level
|
// Build mip in place for the next mip level
|
||||||
if ( mip < mipCount - 1 )
|
if ( mip < mipCount - 1 )
|
||||||
{
|
{
|
||||||
|
@ -786,32 +811,58 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
||||||
// 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-2) {
|
||||||
const int index = tex - vk_textures;
|
const int index = tex - vk_textures;
|
||||||
VkDescriptorImageInfo dii_tmp;
|
const VkDescriptorSet ds = vk_desc.sets[vk_desc.next_free++];
|
||||||
// FIXME handle cubemaps properly w/o this garbage. they should be the same as regular textures.
|
const VkDescriptorSet ds_unorm =
|
||||||
VkDescriptorImageInfo *const dii_tex = (num_layers == 1) ? tglob.dii_all_textures + index : &dii_tmp;
|
(colorspace_hint == kColorspaceGamma && tex->vk.image.view_unorm != VK_NULL_HANDLE)
|
||||||
*dii_tex = (VkDescriptorImageInfo){
|
? vk_desc.sets[vk_desc.next_free++] : VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
const VkDescriptorImageInfo dii = {
|
||||||
.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,
|
||||||
.sampler = pickSamplerForFlags( tex->flags ),
|
.sampler = pickSamplerForFlags( tex->flags ),
|
||||||
};
|
};
|
||||||
const VkWriteDescriptorSet wds[] = { {
|
|
||||||
|
const VkDescriptorImageInfo dii_unorm = {
|
||||||
|
.imageView = tex->vk.image.view_unorm,
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
.sampler = dii.sampler,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkWriteDescriptorSet wds[2] = { {
|
||||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
.dstBinding = 0,
|
.dstBinding = 0,
|
||||||
.dstArrayElement = 0,
|
.dstArrayElement = 0,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
.pImageInfo = dii_tex,
|
.pImageInfo = &dii,
|
||||||
.dstSet = tex->vk.descriptor = vk_desc.sets[vk_desc.next_free++],
|
.dstSet = ds,
|
||||||
|
}, {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.dstBinding = 0,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.pImageInfo = &dii_unorm,
|
||||||
|
.dstSet = ds_unorm,
|
||||||
}};
|
}};
|
||||||
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
vkUpdateDescriptorSets(vk_core.device, ds_unorm != VK_NULL_HANDLE ? 2 : 1 , wds, 0, NULL);
|
||||||
|
|
||||||
|
// FIXME handle cubemaps properly w/o this garbage. they should be the same as regular textures.
|
||||||
|
if (num_layers == 1) {
|
||||||
|
tglob.dii_all_textures[index] = dii;
|
||||||
|
}
|
||||||
|
|
||||||
|
tex->vk.descriptor_unorm = ds_unorm != VK_NULL_HANDLE ? ds_unorm : ds;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tex->vk.descriptor = VK_NULL_HANDLE;
|
tex->vk.descriptor_unorm = VK_NULL_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_textures.stats.size_total += tex->total_size;
|
||||||
|
g_textures.stats.count++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,18 +896,270 @@ const byte* VK_TextureData( unsigned int texnum )
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
|
||||||
{
|
|
||||||
vk_texture_t *tex;
|
|
||||||
rgbdata_t *pic;
|
|
||||||
uint picFlags = 0;
|
|
||||||
|
|
||||||
if( !Common_CheckTexName( name ))
|
#define KTX_IDENTIFIER_SIZE 12
|
||||||
|
static const char k_ktx2_identifier[KTX_IDENTIFIER_SIZE] = {
|
||||||
|
'\xAB', 'K', 'T', 'X', ' ', '2', '0', '\xBB', '\r', '\n', '\x1A', '\n'
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t vkFormat;
|
||||||
|
uint32_t typeSize;
|
||||||
|
uint32_t pixelWidth;
|
||||||
|
uint32_t pixelHeight;
|
||||||
|
uint32_t pixelDepth;
|
||||||
|
uint32_t layerCount;
|
||||||
|
uint32_t faceCount;
|
||||||
|
uint32_t levelCount;
|
||||||
|
uint32_t supercompressionScheme;
|
||||||
|
} ktx_header_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t dfdByteOffset;
|
||||||
|
uint32_t dfdByteLength;
|
||||||
|
uint32_t kvdByteOffset;
|
||||||
|
uint32_t kvdByteLength;
|
||||||
|
uint64_t sgdByteOffset;
|
||||||
|
uint64_t sgdByteLength;
|
||||||
|
} ktx_index_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t byteOffset;
|
||||||
|
uint64_t byteLength;
|
||||||
|
uint64_t uncompressedByteLength;
|
||||||
|
} ktx_level_t;
|
||||||
|
|
||||||
|
static int loadKtx2( const char *name ) {
|
||||||
|
fs_offset_t size = 0;
|
||||||
|
byte *data = gEngine.fsapi->LoadFile( name, &size, false );
|
||||||
|
|
||||||
|
DEBUG("Loading KTX2 file \"%s\", exists=%d", name, data != 0);
|
||||||
|
|
||||||
|
if ( !data )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// see if already loaded
|
const ktx_header_t* header;
|
||||||
if(( tex = Common_TextureForName( name )))
|
const ktx_index_t* index;
|
||||||
return (tex - vk_textures);
|
const ktx_level_t* levels;
|
||||||
|
vk_texture_t* tex = NULL;
|
||||||
|
|
||||||
|
if (size < (sizeof k_ktx2_identifier + sizeof(ktx_header_t) + sizeof(ktx_index_t) + sizeof(ktx_level_t))) {
|
||||||
|
ERR("KTX2 file \"%s\" seems truncated", name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(data, k_ktx2_identifier, sizeof k_ktx2_identifier) != 0) {
|
||||||
|
ERR("KTX2 file \"%s\" identifier is invalid", name);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
header = (const ktx_header_t*)(data + sizeof k_ktx2_identifier);
|
||||||
|
index = (const ktx_index_t*)(data + sizeof k_ktx2_identifier + sizeof(ktx_header_t));
|
||||||
|
levels = (const ktx_level_t*)(data + sizeof k_ktx2_identifier + sizeof(ktx_header_t) + sizeof(ktx_index_t));
|
||||||
|
|
||||||
|
DEBUG("KTX2 file \"%s\"", name);
|
||||||
|
DEBUG(" header:");
|
||||||
|
#define X(field) DEBUG(" " # field "=%d", header->field);
|
||||||
|
DEBUG(" vkFormat = %s(%d)", R_VkFormatName(header->vkFormat), header->vkFormat);
|
||||||
|
X(typeSize)
|
||||||
|
X(pixelWidth)
|
||||||
|
X(pixelHeight)
|
||||||
|
X(pixelDepth)
|
||||||
|
X(layerCount)
|
||||||
|
X(faceCount)
|
||||||
|
X(levelCount)
|
||||||
|
X(supercompressionScheme)
|
||||||
|
#undef X
|
||||||
|
DEBUG(" index:");
|
||||||
|
#define X(field) DEBUG(" " # field "=%llu", (unsigned long long)index->field);
|
||||||
|
X(dfdByteOffset)
|
||||||
|
X(dfdByteLength)
|
||||||
|
X(kvdByteOffset)
|
||||||
|
X(kvdByteLength)
|
||||||
|
X(sgdByteOffset)
|
||||||
|
X(sgdByteLength)
|
||||||
|
#undef X
|
||||||
|
|
||||||
|
for (int mip = 0; mip < header->levelCount; ++mip) {
|
||||||
|
const ktx_level_t* const level = levels + mip;
|
||||||
|
DEBUG(" level[%d]:", mip);
|
||||||
|
DEBUG(" byteOffset=%llu", (unsigned long long)level->byteOffset);
|
||||||
|
DEBUG(" byteLength=%llu", (unsigned long long)level->byteLength);
|
||||||
|
DEBUG(" uncompressedByteLength=%llu", (unsigned long long)level->uncompressedByteLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const uint32_t flags = 0;
|
||||||
|
tex = Common_AllocTexture( name, flags );
|
||||||
|
if (!tex)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME check that format is supported
|
||||||
|
// FIXME layers == 0
|
||||||
|
// FIXME has_alpha
|
||||||
|
// FIXME no supercompressionScheme
|
||||||
|
|
||||||
|
// 1. Create image
|
||||||
|
{
|
||||||
|
const r_vk_image_create_t create = {
|
||||||
|
.debug_name = tex->name,
|
||||||
|
.width = header->pixelWidth,
|
||||||
|
.height = header->pixelHeight,
|
||||||
|
.mips = header->levelCount,
|
||||||
|
.layers = 1, // TODO or 6 for cubemap; header->faceCount
|
||||||
|
.format = header->vkFormat,
|
||||||
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
|
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||||
|
// FIXME find out if there's alpha
|
||||||
|
.flags = 0,
|
||||||
|
};
|
||||||
|
tex->vk.image = R_VkImageCreate(&create);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Prep cmdbuf, barrier, etc
|
||||||
|
{
|
||||||
|
VkImageMemoryBarrier image_barrier = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
|
.image = tex->vk.image.image,
|
||||||
|
.srcAccessMask = 0,
|
||||||
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
.subresourceRange = (VkImageSubresourceRange) {
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = header->levelCount,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1, // TODO cubemap
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
// cmdbuf may become invalidated in locks in the loops below
|
||||||
|
const VkCommandBuffer cmdbuf = R_VkStagingGetCommandBuffer();
|
||||||
|
vkCmdPipelineBarrier(cmdbuf,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
0, 0, NULL, 0, NULL, 1, &image_barrier);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. For levels
|
||||||
|
// 3.1 upload
|
||||||
|
for (int mip = 0; mip < header->levelCount; ++mip) {
|
||||||
|
const ktx_level_t* const level = levels + mip;
|
||||||
|
const uint32_t width = Q_max(1, header->pixelWidth >> mip);
|
||||||
|
const uint32_t height = Q_max(1, header->pixelHeight >> mip);
|
||||||
|
const size_t mip_size = level->byteLength;
|
||||||
|
const uint32_t texel_block_size = R_VkImageFormatTexelBlockSize(header->vkFormat);
|
||||||
|
const void* const image_data = data + level->byteOffset;
|
||||||
|
const vk_staging_image_args_t staging_args = {
|
||||||
|
.image = tex->vk.image.image,
|
||||||
|
.region = (VkBufferImageCopy) {
|
||||||
|
.bufferOffset = 0,
|
||||||
|
.bufferRowLength = 0,
|
||||||
|
.bufferImageHeight = 0,
|
||||||
|
.imageSubresource = (VkImageSubresourceLayers){
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.mipLevel = mip,
|
||||||
|
.baseArrayLayer = 0, // TODO cubemap
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
.imageExtent = (VkExtent3D){
|
||||||
|
.width = width,
|
||||||
|
.height = height,
|
||||||
|
.depth = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
|
.size = mip_size,
|
||||||
|
.alignment = texel_block_size,
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
const vk_staging_region_t staging = R_VkStagingLockForImage(staging_args);
|
||||||
|
ASSERT(staging.ptr);
|
||||||
|
memcpy(staging.ptr, image_data, mip_size);
|
||||||
|
tex->total_size += mip_size;
|
||||||
|
R_VkStagingUnlock(staging.handle);
|
||||||
|
}
|
||||||
|
} // for levels
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO Don't change layout here. Alternatively:
|
||||||
|
// I. Attach layout metadata to the image, and request its change next time it is used.
|
||||||
|
// II. Build-in layout transfer to staging commit and do it there on commit.
|
||||||
|
const VkCommandBuffer cmdbuf = R_VkStagingCommit()->cmdbuf;
|
||||||
|
|
||||||
|
// 5.2 image:layout:DST -> image:layout:SAMPLED
|
||||||
|
// 5.2.1 transitionToLayout(DST -> SHADER_READ_ONLY)
|
||||||
|
image_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
image_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
image_barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
image_barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
image_barrier.subresourceRange = (VkImageSubresourceRange){
|
||||||
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = header->levelCount,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1, // TODO cubemap
|
||||||
|
};
|
||||||
|
vkCmdPipelineBarrier(cmdbuf,
|
||||||
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, // FIXME incorrect, we also use them in compute and potentially ray tracing shaders
|
||||||
|
0, 0, NULL, 0, NULL, 1, &image_barrier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// KTX2 textures are inaccessible from trad renderer (for now)
|
||||||
|
tex->vk.descriptor_unorm = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
const int num_layers = 1; // TODO cubemap
|
||||||
|
const int index = tex - vk_textures;
|
||||||
|
VkDescriptorImageInfo dii_tmp;
|
||||||
|
// FIXME handle cubemaps properly w/o this garbage. they should be the same as regular textures.
|
||||||
|
VkDescriptorImageInfo *const dii_tex = (num_layers == 1) ? tglob.dii_all_textures + index : &dii_tmp;
|
||||||
|
*dii_tex = (VkDescriptorImageInfo){
|
||||||
|
.imageView = tex->vk.image.view,
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||||
|
.sampler = pickSamplerForFlags( tex->flags ),
|
||||||
|
};
|
||||||
|
const VkWriteDescriptorSet wds[] = { {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||||
|
.dstBinding = 0,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||||
|
.pImageInfo = dii_tex,
|
||||||
|
.dstSet = vk_desc.sets[vk_desc.next_free++],
|
||||||
|
}};
|
||||||
|
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_textures.stats.size_total += tex->total_size;
|
||||||
|
g_textures.stats.count++;
|
||||||
|
|
||||||
|
tex->width = header->pixelWidth;
|
||||||
|
tex->height = header->pixelHeight;
|
||||||
|
|
||||||
|
goto finalize;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (tex)
|
||||||
|
memset( tex, 0, sizeof( vk_texture_t ));
|
||||||
|
|
||||||
|
finalize:
|
||||||
|
Mem_Free( data );
|
||||||
|
return (tex - vk_textures);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loadTextureUsingEngine( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint ) {
|
||||||
|
uint picFlags = 0;
|
||||||
|
|
||||||
if( FBitSet( flags, TF_NOFLIP_TGA ))
|
if( FBitSet( flags, TF_NOFLIP_TGA ))
|
||||||
SetBits( picFlags, IL_DONTFLIP_TGA );
|
SetBits( picFlags, IL_DONTFLIP_TGA );
|
||||||
|
@ -867,16 +1170,16 @@ int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
||||||
// set some image flags
|
// set some image flags
|
||||||
gEngine.Image_SetForceFlags( picFlags );
|
gEngine.Image_SetForceFlags( picFlags );
|
||||||
|
|
||||||
pic = gEngine.FS_LoadImage( name, buf, size );
|
rgbdata_t *const pic = gEngine.FS_LoadImage( name, buf, size );
|
||||||
if( !pic ) return 0; // couldn't loading image
|
if( !pic ) return 0; // couldn't loading image
|
||||||
|
|
||||||
// allocate the new one
|
// allocate the new one
|
||||||
tex = Common_AllocTexture( name, flags );
|
vk_texture_t* const tex = Common_AllocTexture( name, flags );
|
||||||
|
|
||||||
// upload texture
|
// upload texture
|
||||||
VK_ProcessImage( tex, pic );
|
VK_ProcessImage( tex, pic );
|
||||||
|
|
||||||
if( !uploadTexture( tex, &pic, 1, false ))
|
if( !uploadTexture( tex, &pic, 1, false, colorspace_hint ))
|
||||||
{
|
{
|
||||||
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
|
||||||
|
@ -892,17 +1195,43 @@ 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 ) {
|
static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint ) {
|
||||||
vk_texture_t *tex;
|
|
||||||
if( !Common_CheckTexName( name ))
|
if( !Common_CheckTexName( name ))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// free if already loaded
|
// see if already loaded
|
||||||
if(( tex = Common_TextureForName( name ))) {
|
vk_texture_t *tex = Common_TextureForName( name );
|
||||||
VK_FreeTexture( tex - vk_textures );
|
if( tex )
|
||||||
|
return (tex - vk_textures);
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *ext = Q_strrchr(name, '.');
|
||||||
|
if (Q_strcmp(ext, ".ktx2") == 0) {
|
||||||
|
return loadKtx2(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return VK_LoadTexture( name, buf, size, flags );
|
return loadTextureUsingEngine(name, buf, size, flags, colorspace_hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
int VK_LoadTextureExternal( const char *name, const byte *buf, size_t size, int flags ) {
|
||||||
|
return loadTextureInternal(name, buf, size, flags, kColorspaceGamma);
|
||||||
|
}
|
||||||
|
|
||||||
|
int R_VkLoadTexture( const char *filename, colorspace_hint_e colorspace, qboolean force_reload) {
|
||||||
|
vk_texture_t *tex;
|
||||||
|
if( !Common_CheckTexName( filename ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (force_reload) {
|
||||||
|
// free if already loaded
|
||||||
|
// TODO consider leaving intact if loading failed
|
||||||
|
if(( tex = Common_TextureForName( filename ))) {
|
||||||
|
VK_FreeTexture( tex - vk_textures );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return loadTextureInternal( filename, NULL, 0, 0, colorspace );
|
||||||
}
|
}
|
||||||
|
|
||||||
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 )
|
||||||
|
@ -971,7 +1300,9 @@ void VK_FreeTexture( unsigned int texnum ) {
|
||||||
R_VkStagingFlushSync();
|
R_VkStagingFlushSync();
|
||||||
XVK_CHECK(vkDeviceWaitIdle(vk_core.device));
|
XVK_CHECK(vkDeviceWaitIdle(vk_core.device));
|
||||||
|
|
||||||
XVK_ImageDestroy(&tex->vk.image);
|
R_VkImageDestroy(&tex->vk.image);
|
||||||
|
g_textures.stats.size_total -= tex->total_size;
|
||||||
|
g_textures.stats.count--;
|
||||||
memset(tex, 0, sizeof(*tex));
|
memset(tex, 0, sizeof(*tex));
|
||||||
|
|
||||||
tglob.dii_all_textures[texnum] = (VkDescriptorImageInfo){
|
tglob.dii_all_textures[texnum] = (VkDescriptorImageInfo){
|
||||||
|
@ -1009,7 +1340,7 @@ static int loadTextureFromBuffers( const char *name, rgbdata_t *const *const pic
|
||||||
for (int i = 0; i < pic_count; ++i)
|
for (int i = 0; i < pic_count; ++i)
|
||||||
VK_ProcessImage( tex, pic[i] );
|
VK_ProcessImage( tex, pic[i] );
|
||||||
|
|
||||||
if( !uploadTexture( tex, pic, pic_count, false ))
|
if( !uploadTexture( tex, pic, pic_count, false, kColorspaceGamma ))
|
||||||
{
|
{
|
||||||
memset( tex, 0, sizeof( vk_texture_t ));
|
memset( tex, 0, sizeof( vk_texture_t ));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1037,7 +1368,9 @@ int XVK_TextureLookupF( const char *fmt, ...) {
|
||||||
|
|
||||||
static void unloadSkybox( void ) {
|
static void unloadSkybox( void ) {
|
||||||
if (tglob.skybox_cube.vk.image.image) {
|
if (tglob.skybox_cube.vk.image.image) {
|
||||||
XVK_ImageDestroy(&tglob.skybox_cube.vk.image);
|
R_VkImageDestroy(&tglob.skybox_cube.vk.image);
|
||||||
|
g_textures.stats.size_total -= tglob.skybox_cube.total_size;
|
||||||
|
g_textures.stats.count--;
|
||||||
memset(&tglob.skybox_cube, 0, sizeof(tglob.skybox_cube));
|
memset(&tglob.skybox_cube, 0, sizeof(tglob.skybox_cube));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,7 +1466,7 @@ static qboolean loadSkybox( const char *prefix, int style ) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
Q_strncpy( tglob.skybox_cube.name, prefix, sizeof( tglob.skybox_cube.name ));
|
Q_strncpy( tglob.skybox_cube.name, prefix, sizeof( tglob.skybox_cube.name ));
|
||||||
success = uploadTexture(&tglob.skybox_cube, sides, 6, true);
|
success = uploadTexture(&tglob.skybox_cube, sides, 6, true, kColorspaceGamma);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
for (int j = 0; j < i; ++j)
|
for (int j = 0; j < i; ++j)
|
||||||
|
|
|
@ -16,12 +16,14 @@ typedef struct vk_texture_s
|
||||||
uint texnum;
|
uint texnum;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
xvk_image_t image;
|
r_vk_image_t image;
|
||||||
VkDescriptorSet descriptor;
|
VkDescriptorSet descriptor_unorm;
|
||||||
} vk;
|
} vk;
|
||||||
|
|
||||||
uint hashValue;
|
uint hashValue;
|
||||||
struct vk_texture_s *nextHash;
|
struct vk_texture_s *nextHash;
|
||||||
|
|
||||||
|
int total_size;
|
||||||
} vk_texture_t;
|
} vk_texture_t;
|
||||||
|
|
||||||
#define MAX_LIGHTMAPS 256
|
#define MAX_LIGHTMAPS 256
|
||||||
|
@ -54,6 +56,7 @@ typedef struct vk_textures_global_s
|
||||||
vk_texture_t skybox_cube;
|
vk_texture_t skybox_cube;
|
||||||
vk_texture_t cubemap_placeholder;
|
vk_texture_t cubemap_placeholder;
|
||||||
|
|
||||||
|
// All textures descriptors in their native formats used for RT
|
||||||
VkDescriptorImageInfo dii_all_textures[MAX_TEXTURES];
|
VkDescriptorImageInfo dii_all_textures[MAX_TEXTURES];
|
||||||
|
|
||||||
// FIXME this should not exist, all textures should have their own samplers based on flags
|
// FIXME this should not exist, all textures should have their own samplers based on flags
|
||||||
|
@ -73,18 +76,24 @@ void initTextures( void );
|
||||||
void destroyTextures( void );
|
void destroyTextures( void );
|
||||||
vk_texture_t *findTexture(int index);
|
vk_texture_t *findTexture(int index);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kColorspaceNative,
|
||||||
|
kColorspaceLinear,
|
||||||
|
kColorspaceGamma,
|
||||||
|
} colorspace_hint_e;
|
||||||
|
|
||||||
// Public API functions
|
// Public API functions
|
||||||
int VK_FindTexture( const char *name );
|
int VK_FindTexture( const char *name );
|
||||||
const char* VK_TextureName( unsigned int texnum );
|
const char* VK_TextureName( unsigned int texnum );
|
||||||
const byte* VK_TextureData( unsigned int texnum );
|
const byte* VK_TextureData( unsigned int texnum );
|
||||||
int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags );
|
int VK_LoadTextureExternal( const char *name, const byte *buf, size_t size, int 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 );
|
||||||
int VK_LoadTextureArray( const char **names, int flags );
|
int VK_LoadTextureArray( const char **names, int flags );
|
||||||
int VK_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
|
int VK_CreateTextureArray( const char *name, int width, int height, int depth, const void *buffer, texFlags_t flags );
|
||||||
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 R_VkLoadTexture( const char *filename, colorspace_hint_e colorspace, qboolean force_reload);
|
||||||
|
|
||||||
int XVK_TextureLookupF( const char *fmt, ...);
|
int XVK_TextureLookupF( const char *fmt, ...);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue