Merge pull request #597 from w23/srgb-gamma
sRGB-γ all the things - [x] Makes all textures SRGB by default - [x] For traditional renderer: convert back to SRGB space like it's 1998 again - [x] Make different `VkImageView`s, for linear (trad) and SRGB (rt) to avoid extra conversion - see https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#formats-compatibility-classes supported surface formats, and also whether the image can be used as a storage destination in compute shader. - [x] Improve `view_unorm` handling: - [x] Don't create a separate view for natively `UNORM` - [x] Create fallback - [x] Use "native" hint for pbr base_color - [x] Remove `test_val` from shaders - [x] Do model and material colors srgb-linear conversion in C - [x] Investigate lighting brightness - Nihrena neponyatno. Problems caused by this amazing change: - Undesired interpolation artifacts: #599 (see discussion below). - Dark places are too dark (caused by more correct linear-to-sRGB conversion that differs from the fast one for smaller values). - Lighting looks a bit different (probably has the same cause as above)
This commit is contained in:
commit
82dea7a86b
|
@ -88,13 +88,14 @@ bool getHit(vec3 origin, vec3 direction, inout RayPayloadPrimary payload) {
|
|||
//L = rayQueryGetIntersectionTEXT(rq, true);
|
||||
return true;
|
||||
}
|
||||
const int INDIRECT_SCALE = 2;
|
||||
|
||||
void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specular) {
|
||||
diffuse = vec3(0.);
|
||||
specular = vec3(0.);
|
||||
|
||||
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;
|
||||
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() {
|
||||
const ivec2 pix = ivec2(gl_GlobalInvocationID);
|
||||
|
|
|
@ -30,6 +30,7 @@ const float dlight_attenuation_const = 5000.;
|
|||
void main() {
|
||||
outColor = vec4(0.);
|
||||
const vec4 tex_color = texture(sTexture0, vTexture0);
|
||||
|
||||
// TODO make sure textures are premultiplied alpha
|
||||
const vec4 baseColor = vColor * tex_color;
|
||||
|
||||
|
@ -48,6 +49,4 @@ void main() {
|
|||
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 = 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
|
||||
#define LINEARtoSRGB OECF_sRGBFast
|
||||
#define SRGBtoLINEAR sRGB_OECFFast
|
||||
|
@ -63,3 +63,5 @@ vec3 OECF_sRGBFast(const vec3 linear) {
|
|||
vec4 OECF_sRGBFast(const vec4 linear) {
|
||||
return vec4(pow(linear.rgb, vec3(1.0 / 2.2)), linear.w);
|
||||
}
|
||||
|
||||
#endif //ifndef RT_COLOR_SPACES_GLSL_INCLUDED
|
||||
|
|
|
@ -36,11 +36,13 @@ layout(set = 0, binding = 15, rgba16f) uniform image2D prev_temporal_diffuse;
|
|||
layout(set = 0, binding = 16, rgba16f) uniform image2D out_temporal_specular;
|
||||
layout(set = 0, binding = 17, rgba16f) uniform image2D prev_temporal_specular;
|
||||
|
||||
//layout(set = 0, binding = 19) uniform sampler2D textures[MAX_TEXTURES];
|
||||
|
||||
const int INDIRECT_SCALE = 2;
|
||||
|
||||
//#define DEBUG_TEXTURE normals_gs
|
||||
//#define DEBUG_TEXTURE emissive
|
||||
//#define DEBUG_TEXTURE base_color_a
|
||||
//#define DEBUG_TEXTURE light_point_diffuse
|
||||
//#define DEBUG_NORMAL
|
||||
//layout(set = 0, binding = 18, rgba8) uniform readonly image2D material_rmxx;
|
||||
|
@ -194,9 +196,31 @@ void main() {
|
|||
/* } */
|
||||
|
||||
#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;
|
||||
#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(geometry_prev_position, pix).rgb/50.), 0.)); return;
|
||||
|
||||
|
@ -270,7 +294,7 @@ void main() {
|
|||
//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 *= base_color_a.rgb;
|
||||
colour += imageLoad(emissive, pix).rgb;
|
||||
colour = LINEARtoSRGB(colour);
|
||||
|
|
|
@ -107,13 +107,13 @@ void main() {
|
|||
L = rayQueryGetIntersectionTEXT(rq, true);
|
||||
} else {
|
||||
// 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);
|
||||
|
||||
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_material_rmxx, pix, vec4(payload.material_rmxx.rg, 0, uintToFloat01(xxhash32(debug_geometry_index))));
|
||||
imageStore(out_material_rmxx, pix, payload.material_rmxx);
|
||||
|
|
|
@ -30,7 +30,7 @@ void main() {
|
|||
const Kusok kusok = getKusok(geom.kusok_index);
|
||||
|
||||
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;
|
||||
} else {
|
||||
const vec4 color = getModelHeader(gl_InstanceID).color * kusok.material.base_color;
|
||||
|
@ -55,7 +55,7 @@ void main() {
|
|||
#if 1
|
||||
// Real correct emissive color
|
||||
//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
|
||||
// Fake texture color
|
||||
if (any(greaterThan(kusok.emissive, vec3(0.))))
|
||||
|
|
|
@ -31,10 +31,10 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
|
|||
const Material material = kusok.material;
|
||||
|
||||
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;
|
||||
} else {
|
||||
payload.base_color_a = SRGBtoLINEAR(sampleTexture(material.tex_base_color, geom.uv, geom.uv_lods));
|
||||
payload.base_color_a = sampleTexture(material.tex_base_color, geom.uv, geom.uv_lods);
|
||||
payload.material_rmxx.r = sampleTexture(material.tex_roughness, geom.uv, geom.uv_lods).r * material.roughness;
|
||||
payload.material_rmxx.g = sampleTexture(material.tex_metalness, geom.uv, geom.uv_lods).r * material.metalness;
|
||||
|
||||
|
@ -99,7 +99,7 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) {
|
|||
|
||||
const int model_index = rayQueryGetIntersectionInstanceIdEXT(rq, true);
|
||||
const ModelHeader model = getModelHeader(model_index);
|
||||
const vec4 color = model.color * SRGBtoLINEAR(kusok.material.base_color); // FIXME why is material.base_color in gamma space?
|
||||
const vec4 color = model.color * kusok.material.base_color;
|
||||
|
||||
payload.base_color_a *= color;
|
||||
payload.emissive.rgb *= color.rgb;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef RT_GEOMETRY_GLSL_INCLUDED
|
||||
#define RT_GEOMETRY_GLSL_INCLUDED
|
||||
#include "utils.glsl"
|
||||
#include "color_spaces.glsl"
|
||||
|
||||
// Taken from Journal of Computer Graphics Techniques, Vol. 10, No. 1, 2021.
|
||||
// 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 vec4 colors[3] = {
|
||||
unpackUnorm4x8(GET_VERTEX(vi1).color),
|
||||
unpackUnorm4x8(GET_VERTEX(vi2).color),
|
||||
unpackUnorm4x8(GET_VERTEX(vi3).color),
|
||||
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi1).color)),
|
||||
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi2).color)),
|
||||
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi3).color)),
|
||||
};
|
||||
|
||||
MiniGeometry ret;
|
||||
|
|
|
@ -53,14 +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 mm_color = model.color * kusok.material.base_color;
|
||||
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;
|
||||
|
||||
/* TODO: I think it should be like this instead:
|
||||
const vec4 texture_color = SRGBtoLINEAR(texture(textures[nonuniformEXT(kusok.material.tex_base_color)], geom.uv));
|
||||
const vec4 mm_color = SRGBtoLINEAR(model.color) * SRGBtoLINEAR(kusok.material.base_color);
|
||||
float alpha = mm_color.a * texture_color.a * geom.vertex_color.a;
|
||||
vec3 color = mm_color.rgb * texture_color.rgb * geom.vertex_color.rgb * alpha;
|
||||
*/
|
||||
|
||||
if (model.mode == MATERIAL_MODE_BLEND_GLOW) {
|
||||
// Glow is additive + small overshoot
|
||||
|
|
|
@ -12,7 +12,8 @@ typedef struct descriptor_pool_s
|
|||
int next_free;
|
||||
//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;
|
||||
|
||||
// FIXME HOW THE F
|
||||
|
@ -31,7 +32,7 @@ typedef union {
|
|||
VkDescriptorImageInfo image;
|
||||
VkDescriptorImageInfo *image_array;
|
||||
VkWriteDescriptorSetAccelerationStructureKHR accel;
|
||||
const struct xvk_image_s *image_object;
|
||||
const struct r_vk_image_s *image_object;
|
||||
} vk_descriptor_value_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
@ -259,6 +259,7 @@ void VK_RenderFrame( const struct ref_viewpass_s *rvp )
|
|||
}
|
||||
|
||||
static void enqueueRendering( vk_combuf_t* combuf, qboolean draw ) {
|
||||
APROF_SCOPE_DECLARE_BEGIN(enqueue, __FUNCTION__);
|
||||
const VkClearValue clear_value[] = {
|
||||
{.color = {{1., 0., 0., 0.}}},
|
||||
{.depthStencil = {1., 0.}} // TODO reverse-z
|
||||
|
@ -307,10 +308,12 @@ static void enqueueRendering( vk_combuf_t* combuf, qboolean draw ) {
|
|||
vkCmdEndRenderPass(cmdbuf);
|
||||
|
||||
g_frame.current.phase = Phase_RenderingEnqueued;
|
||||
APROF_SCOPE_END(enqueue);
|
||||
}
|
||||
|
||||
// FIXME pass frame, not combuf (possible desync)
|
||||
static void submit( vk_combuf_t* combuf, qboolean wait, qboolean draw ) {
|
||||
APROF_SCOPE_DECLARE_BEGIN(submit, __FUNCTION__);
|
||||
ASSERT(g_frame.current.phase == Phase_RenderingEnqueued);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
APROF_SCOPE_END(submit);
|
||||
}
|
||||
|
||||
inline static VkCommandBuffer currentCommandBuffer( void ) {
|
||||
|
@ -510,7 +515,7 @@ static qboolean canBlitFromSwapchainToFormat( VkFormat dest_format ) {
|
|||
|
||||
static rgbdata_t *XVK_ReadPixels( void ) {
|
||||
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;
|
||||
rgbdata_t *r_shot = NULL;
|
||||
qboolean blit = canBlitFromSwapchainToFormat( dest_format );
|
||||
|
@ -525,7 +530,7 @@ static rgbdata_t *XVK_ReadPixels( void ) {
|
|||
|
||||
// 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",
|
||||
.width = vk_frame.width,
|
||||
.height = vk_frame.height,
|
||||
|
@ -534,11 +539,10 @@ static rgbdata_t *XVK_ReadPixels( void ) {
|
|||
.format = dest_format,
|
||||
.tiling = VK_IMAGE_TILING_LINEAR,
|
||||
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.has_alpha = false,
|
||||
.is_cubemap = false,
|
||||
.flags = 0,
|
||||
.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
|
||||
|
@ -700,7 +704,7 @@ static rgbdata_t *XVK_ReadPixels( void ) {
|
|||
}
|
||||
}
|
||||
|
||||
XVK_ImageDestroy( &dest_image );
|
||||
R_VkImageDestroy( &dest_image );
|
||||
|
||||
return r_shot;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "vk_image.h"
|
||||
#include "vk_logs.h"
|
||||
|
||||
static const VkImageUsageFlags usage_bits_implying_views =
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
|
@ -16,11 +17,92 @@ static const VkImageUsageFlags usage_bits_implying_views =
|
|||
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);
|
||||
xvk_image_t image = {0};
|
||||
r_vk_image_t image = {0};
|
||||
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 = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
|
@ -35,11 +117,15 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
|||
.usage = create->usage,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.flags = create->is_cubemap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0,
|
||||
.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));
|
||||
|
||||
image.format = ici.format;
|
||||
|
||||
if (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));
|
||||
|
||||
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,
|
||||
.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,
|
||||
.image = image.image,
|
||||
.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.baseArrayLayer = 0,
|
||||
.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));
|
||||
|
||||
if (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;
|
||||
|
@ -73,11 +170,17 @@ xvk_image_t XVK_ImageCreate(const xvk_image_create_t *create) {
|
|||
return image;
|
||||
}
|
||||
|
||||
void XVK_ImageDestroy(xvk_image_t *img) {
|
||||
vkDestroyImageView(vk_core.device, img->view, NULL);
|
||||
void R_VkImageDestroy(r_vk_image_t *img) {
|
||||
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);
|
||||
|
||||
VK_DevMemFree(&img->devmem);
|
||||
*img = (xvk_image_t){0};
|
||||
*img = (r_vk_image_t){0};
|
||||
}
|
||||
|
||||
void R_VkImageClear(VkCommandBuffer cmdbuf, VkImage image) {
|
||||
|
|
|
@ -2,14 +2,25 @@
|
|||
#include "vk_core.h"
|
||||
#include "vk_devmem.h"
|
||||
|
||||
typedef struct xvk_image_s {
|
||||
typedef struct r_vk_image_s {
|
||||
vk_devmem_t devmem;
|
||||
VkImage image;
|
||||
VkImageView view;
|
||||
|
||||
// Optional, created by kVkImageFlagCreateUnormView
|
||||
// Used for sRGB-γ-unaware traditional renderer
|
||||
VkImageView view_unorm;
|
||||
|
||||
uint32_t width, height;
|
||||
int mips;
|
||||
} xvk_image_t;
|
||||
VkFormat format;
|
||||
} r_vk_image_t;
|
||||
|
||||
enum {
|
||||
kVkImageFlagHasAlpha = (1<<0),
|
||||
kVkImageFlagIsCubemap = (1<<1),
|
||||
kVkImageFlagCreateUnormView = (1<<2),
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char *debug_name;
|
||||
|
@ -18,13 +29,12 @@ typedef struct {
|
|||
VkFormat format;
|
||||
VkImageTiling tiling;
|
||||
VkImageUsageFlags usage;
|
||||
qboolean has_alpha;
|
||||
qboolean is_cubemap;
|
||||
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);
|
||||
void XVK_ImageDestroy(xvk_image_t *img);
|
||||
r_vk_image_t R_VkImageCreate(const r_vk_image_create_t *create);
|
||||
void R_VkImageDestroy(r_vk_image_t *img);
|
||||
|
||||
void R_VkImageClear(VkCommandBuffer cmdbuf, VkImage image);
|
||||
|
||||
|
|
|
@ -1263,6 +1263,7 @@ static void uploadPointLights( struct LightsMetadata *metadata ) {
|
|||
}
|
||||
|
||||
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) {
|
||||
.buffer = g_lights_.buffer.buffer,
|
||||
.offset = 0,
|
||||
|
@ -1287,6 +1288,8 @@ vk_lights_bindings_t VK_LightsUpload( void ) {
|
|||
|
||||
g_lights_.frame_sequence++;
|
||||
|
||||
APROF_SCOPE_END(upload);
|
||||
|
||||
return (vk_lights_bindings_t){
|
||||
.buffer = g_lights_.buffer.buffer,
|
||||
.metadata = {
|
||||
|
|
|
@ -75,9 +75,9 @@ static struct {
|
|||
uint64_t texture_load_duration_ns;
|
||||
} 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 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);
|
||||
g_stats.texture_loads++;
|
||||
g_stats.texture_load_duration_ns += aprof_time_now_ns() - load_begin_ns;
|
||||
|
@ -206,11 +206,11 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
|
|||
continue;
|
||||
}
|
||||
|
||||
#define LOAD_TEXTURE_FOR(name, field) do { \
|
||||
#define LOAD_TEXTURE_FOR(name, field, colorspace) do { \
|
||||
if (name[0] != '\0') { \
|
||||
char texture_path[256]; \
|
||||
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) { \
|
||||
ERR("Failed to load texture \"%s\" for "#name"", name); \
|
||||
} else { \
|
||||
|
@ -218,10 +218,10 @@ static void loadMaterialsFromFile( const char *filename, int depth ) {
|
|||
} \
|
||||
}} while(0)
|
||||
|
||||
LOAD_TEXTURE_FOR(basecolor_map, tex_base_color);
|
||||
LOAD_TEXTURE_FOR(normal_map, tex_normalmap);
|
||||
LOAD_TEXTURE_FOR(metal_map, tex_metalness);
|
||||
LOAD_TEXTURE_FOR(roughness_map, tex_roughness);
|
||||
LOAD_TEXTURE_FOR(basecolor_map, tex_base_color, kColorspaceNative);
|
||||
LOAD_TEXTURE_FOR(normal_map, tex_normalmap, kColorspaceLinear);
|
||||
LOAD_TEXTURE_FOR(metal_map, tex_metalness, kColorspaceLinear);
|
||||
LOAD_TEXTURE_FOR(roughness_map, tex_roughness, kColorspaceLinear);
|
||||
|
||||
// If there's no explicit basecolor_map value, use the "for" target texture
|
||||
if (current_material.tex_base_color == -1)
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "vk_common.h"
|
||||
#include "vk_logs.h"
|
||||
|
||||
#include "profiler.h"
|
||||
|
||||
#define LOG_MODULE LogModule_Meatpipe
|
||||
|
||||
#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) {
|
||||
APROF_SCOPE_DECLARE_BEGIN(perform, __FUNCTION__);
|
||||
for (int i = 0; i < mp->passes_count; ++i) {
|
||||
const vk_meatpipe_pass_t *pass = mp->passes + i;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
} // FIXME else what?
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "vk_render.h"
|
||||
#include "vk_logs.h"
|
||||
|
||||
#include "profiler.h"
|
||||
|
||||
#include "xash3d_mathlib.h"
|
||||
|
||||
#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) {
|
||||
APROF_SCOPE_DECLARE_BEGIN(prepare, __FUNCTION__);
|
||||
ASSERT(g_ray_model_state.frame.instances_count > 0);
|
||||
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);
|
||||
}
|
||||
|
||||
APROF_SCOPE_END(prepare);
|
||||
return (vk_resource_t){
|
||||
.type = VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR,
|
||||
.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++);
|
||||
}
|
||||
|
||||
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 ) {
|
||||
if (!model || !model->blas)
|
||||
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->kusochki_offset = kusochki_offset;
|
||||
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);
|
||||
Matrix4x4_Copy(draw_instance->prev_transform_row, args.prev_transform);
|
||||
}
|
||||
|
@ -390,6 +404,7 @@ void RT_DynamicModelShutdown(void) {
|
|||
}
|
||||
|
||||
void RT_DynamicModelProcessFrame(void) {
|
||||
APROF_SCOPE_DECLARE_BEGIN(process, __FUNCTION__);
|
||||
for (int i = 0; i < MATERIAL_MODE_COUNT; ++i) {
|
||||
rt_dynamic_t *const dyn = g_dyn.groups + i;
|
||||
if (!dyn->geometries_count)
|
||||
|
@ -427,6 +442,7 @@ void RT_DynamicModelProcessFrame(void) {
|
|||
tail:
|
||||
dyn->geometries_count = 0;
|
||||
}
|
||||
APROF_SCOPE_END(process);
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
texture = draw->draw.texture;
|
||||
// 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
|
||||
|
@ -784,7 +784,7 @@ void R_RenderModelDraw(const vk_render_model_t *model, r_model_draw_t args) {
|
|||
.material_mode = args.material_mode,
|
||||
.transform = (const matrix3x4*)args.transform,
|
||||
.prev_transform = (const matrix3x4*)args.prev_transform,
|
||||
.color = args.color,
|
||||
.color_srgb = args.color,
|
||||
.dynamic_polylights = model->dynamic_polylights,
|
||||
.dynamic_polylights_count = model->dynamic_polylights_count,
|
||||
.override = {
|
||||
|
|
|
@ -543,7 +543,7 @@ static const ref_interface_t gReffuncs =
|
|||
VK_FindTexture,
|
||||
VK_TextureName,
|
||||
VK_TextureData,
|
||||
VK_LoadTexture,
|
||||
VK_LoadTextureExternal,
|
||||
VK_CreateTexture,
|
||||
VK_LoadTextureArray,
|
||||
VK_CreateTextureArray,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "vk_logs.h"
|
||||
|
||||
#include "alolcator.h"
|
||||
|
||||
#include "profiler.h"
|
||||
|
||||
#include "eiface.h"
|
||||
#include "xash3d_mathlib.h"
|
||||
|
@ -67,7 +67,7 @@ enum {
|
|||
typedef struct {
|
||||
char name[64];
|
||||
vk_resource_t resource;
|
||||
xvk_image_t image;
|
||||
r_vk_image_t image;
|
||||
int refcount;
|
||||
int source_index_plus_1;
|
||||
} rt_resource_t;
|
||||
|
@ -170,6 +170,7 @@ typedef struct {
|
|||
} perform_tracing_args_t;
|
||||
|
||||
static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* args) {
|
||||
APROF_SCOPE_DECLARE_BEGIN(perform, __FUNCTION__);
|
||||
const VkCommandBuffer cmdbuf = combuf->cmdbuf;
|
||||
|
||||
#define RES_SET_BUFFER(name, type_, source_, offset_, size_) \
|
||||
|
@ -238,7 +239,7 @@ static void performTracing( vk_combuf_t *combuf, const perform_tracing_args_t* a
|
|||
|
||||
// Swap resources
|
||||
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->image = src->image;
|
||||
|
@ -338,6 +339,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;
|
||||
}
|
||||
DEBUG_END(cmdbuf);
|
||||
|
||||
APROF_SCOPE_END(perform);
|
||||
}
|
||||
|
||||
static void cleanupResources(void) {
|
||||
|
@ -346,7 +349,7 @@ static void cleanupResources(void) {
|
|||
if (!res->name[0] || res->refcount || !res->image.image)
|
||||
continue;
|
||||
|
||||
XVK_ImageDestroy(&res->image);
|
||||
R_VkImageDestroy(&res->image);
|
||||
res->name[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
@ -387,10 +390,11 @@ static void reloadMainpipe(void) {
|
|||
|
||||
for (int i = 0; i < newpipe->resources_count; ++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,
|
||||
(mr->flags & MEATPIPE_RES_WRITE) ? 'W' : ' ',
|
||||
(mr->flags & MEATPIPE_RES_CREATE) ? 'C' : ' ',
|
||||
R_VkFormatName(mr->image_format),
|
||||
mr->image_format);
|
||||
|
||||
const qboolean create = !!(mr->flags & MEATPIPE_RES_CREATE);
|
||||
|
@ -415,8 +419,11 @@ static void reloadMainpipe(void) {
|
|||
newpipe_out = res;
|
||||
|
||||
if (create) {
|
||||
if (res->image.image == VK_NULL_HANDLE) {
|
||||
const xvk_image_create_t create = {
|
||||
if (res->image.image == VK_NULL_HANDLE || mr->image_format != res->image.format) {
|
||||
if (res->image.image != VK_NULL_HANDLE) {
|
||||
R_VkImageDestroy(&res->image);
|
||||
}
|
||||
const r_vk_image_create_t create = {
|
||||
.debug_name = mr->name,
|
||||
.width = FRAME_WIDTH,
|
||||
.height = FRAME_HEIGHT,
|
||||
|
@ -427,13 +434,10 @@ static void reloadMainpipe(void) {
|
|||
// 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 | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.has_alpha = true,
|
||||
.is_cubemap = false,
|
||||
.flags = kVkImageFlagHasAlpha,
|
||||
};
|
||||
res->image = XVK_ImageCreate(&create);
|
||||
res->image = R_VkImageCreate(&create);
|
||||
Q_strncpy(res->name, mr->name, sizeof(res->name));
|
||||
} else {
|
||||
// TODO if (mr->image_format != res->image.format) { S_ERROR and goto fail }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,7 +497,7 @@ static void reloadMainpipe(void) {
|
|||
|
||||
// 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:
|
||||
// 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.
|
||||
|
||||
g_rtx.mainpipe = newpipe;
|
||||
|
@ -513,6 +517,8 @@ fail:
|
|||
|
||||
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 xvk_ray_frame_images_t* current_frame = g_rtx.frames + (g_rtx.frame_number % 2);
|
||||
|
||||
|
@ -576,6 +582,8 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
|
|||
};
|
||||
performTracing( args->combuf, &trace_args );
|
||||
}
|
||||
|
||||
APROF_SCOPE_END(ray_frame_end);
|
||||
}
|
||||
|
||||
static void reloadPipeline( void ) {
|
||||
|
|
|
@ -58,7 +58,7 @@ qboolean RT_ModelUpdateMaterials(struct rt_model_s *model, const struct vk_rende
|
|||
typedef struct {
|
||||
int material_mode;
|
||||
const matrix3x4 *transform, *prev_transform;
|
||||
const vec4_t *color;
|
||||
const vec4_t *color_srgb;
|
||||
|
||||
struct rt_light_add_polygon_s *dynamic_polylights;
|
||||
int dynamic_polylights_count;
|
||||
|
|
|
@ -230,6 +230,9 @@ int R_FIXME_GetEntityRenderMode( cl_entity_t *ent )
|
|||
}
|
||||
|
||||
void R_SceneMapDestroy( void ) {
|
||||
// Make sure no rendering is happening
|
||||
XVK_CHECK(vkDeviceWaitIdle( vk_core.device ));
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
|
|
|
@ -3337,7 +3337,7 @@ static void R_StudioLoadTexture( model_t *mod, studiohdr_t *phdr, mstudiotexture
|
|||
|
||||
// build the texname
|
||||
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 )
|
||||
{
|
||||
|
|
|
@ -18,7 +18,7 @@ static struct {
|
|||
VkImageView *image_views;
|
||||
VkFramebuffer *framebuffers;
|
||||
|
||||
xvk_image_t depth;
|
||||
r_vk_image_t depth;
|
||||
|
||||
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) {
|
||||
const xvk_image_create_t xic = {
|
||||
const r_vk_image_create_t xic = {
|
||||
.debug_name = "depth",
|
||||
.format = depth_format,
|
||||
.has_alpha = false,
|
||||
.is_cubemap = false,
|
||||
.flags = 0,
|
||||
.mips = 1,
|
||||
.layers = 1,
|
||||
.width = w,
|
||||
|
@ -45,7 +44,7 @@ static void createDepthImage(int w, int h, VkFormat depth_format) {
|
|||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.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 ) {
|
||||
|
@ -56,7 +55,7 @@ static void destroySwapchainAndFramebuffers( VkSwapchainKHR swapchain ) {
|
|||
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);
|
||||
}
|
||||
|
@ -187,7 +186,12 @@ qboolean R_VkSwapchainInit( VkRenderPass render_pass, VkFormat depth_format ) {
|
|||
VkSurfaceCapabilitiesKHR 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.depth_format = depth_format;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ void destroyTextures( void )
|
|||
|
||||
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));
|
||||
|
@ -274,7 +274,7 @@ 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 void VK_CreateInternalTextures( void )
|
||||
{
|
||||
|
@ -350,14 +350,17 @@ static void VK_CreateInternalTextures( void )
|
|||
sides[4] = pic;
|
||||
sides[5] = pic;
|
||||
|
||||
uploadTexture( &tglob.cubemap_placeholder, sides, 6, true );
|
||||
uploadTexture( &tglob.cubemap_placeholder, sides, 6, true, kColorspaceGamma );
|
||||
}
|
||||
}
|
||||
|
||||
static VkFormat VK_GetFormat(pixformat_t format) {
|
||||
static VkFormat VK_GetFormat(pixformat_t format, colorspace_hint_e colorspace_hint ) {
|
||||
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:
|
||||
WARN("FIXME unsupported pixformat_t %d", format);
|
||||
return VK_FORMAT_UNDEFINED;
|
||||
|
@ -550,8 +553,8 @@ static VkSampler pickSamplerForFlags( texFlags_t flags ) {
|
|||
return tglob.default_sampler_fixme;
|
||||
}
|
||||
|
||||
static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers, int num_layers, qboolean cubemap) {
|
||||
const VkFormat format = VK_GetFormat(layers[0]->type);
|
||||
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, colorspace_hint);
|
||||
int mipCount = 0;
|
||||
|
||||
tex->total_size = 0;
|
||||
|
@ -591,7 +594,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
|||
tex->height = layers[0]->height;
|
||||
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
|
||||
// // NOTE: only single uncompressed textures can be resamples, no mips, no layers, no sides
|
||||
|
@ -603,7 +606,7 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
|||
// 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,
|
||||
.width = tex->width,
|
||||
.height = tex->height,
|
||||
|
@ -612,10 +615,12 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
|||
.format = format,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.has_alpha = layers[0]->flags & IMAGE_HAS_ALPHA,
|
||||
.is_cubemap = cubemap,
|
||||
.flags = 0
|
||||
| ((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);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -721,30 +726,54 @@ static qboolean uploadTexture(vk_texture_t *tex, rgbdata_t *const *const layers,
|
|||
// TODO how should we approach this:
|
||||
// - per-texture desc sets can be inconvenient if texture is used in different incompatible contexts
|
||||
// - update descriptor sets in batch?
|
||||
if (vk_desc.next_free != MAX_TEXTURES) {
|
||||
if (vk_desc.next_free < MAX_TEXTURES-2) {
|
||||
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){
|
||||
const VkDescriptorSet ds = vk_desc.sets[vk_desc.next_free++];
|
||||
const VkDescriptorSet ds_unorm =
|
||||
(colorspace_hint == kColorspaceGamma && tex->vk.image.view_unorm != VK_NULL_HANDLE)
|
||||
? vk_desc.sets[vk_desc.next_free++] : VK_NULL_HANDLE;
|
||||
|
||||
const VkDescriptorImageInfo dii = {
|
||||
.imageView = tex->vk.image.view,
|
||||
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
.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,
|
||||
.dstBinding = 0,
|
||||
.dstArrayElement = 0,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = dii_tex,
|
||||
.dstSet = tex->vk.descriptor = vk_desc.sets[vk_desc.next_free++],
|
||||
.pImageInfo = &dii,
|
||||
.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
|
||||
{
|
||||
tex->vk.descriptor = VK_NULL_HANDLE;
|
||||
tex->vk.descriptor_unorm = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
g_textures.stats.size_total += tex->total_size;
|
||||
|
@ -888,7 +917,7 @@ static int loadKtx2( const char *name ) {
|
|||
|
||||
// 1. Create image
|
||||
{
|
||||
const xvk_image_create_t create = {
|
||||
const r_vk_image_create_t create = {
|
||||
.debug_name = tex->name,
|
||||
.width = header->pixelWidth,
|
||||
.height = header->pixelHeight,
|
||||
|
@ -897,10 +926,10 @@ static int loadKtx2( const char *name ) {
|
|||
.format = header->vkFormat,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.has_alpha = false, // FIXME
|
||||
.is_cubemap = false,
|
||||
// FIXME find out if there's alpha
|
||||
.flags = 0,
|
||||
};
|
||||
tex->vk.image = XVK_ImageCreate(&create);
|
||||
tex->vk.image = R_VkImageCreate(&create);
|
||||
}
|
||||
|
||||
// 2. Prep cmdbuf, barrier, etc
|
||||
|
@ -997,9 +1026,13 @@ static int loadKtx2( const char *name ) {
|
|||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
@ -1018,14 +1051,10 @@ static int loadKtx2( const char *name ) {
|
|||
.descriptorCount = 1,
|
||||
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
||||
.pImageInfo = dii_tex,
|
||||
.dstSet = tex->vk.descriptor = vk_desc.sets[vk_desc.next_free++],
|
||||
.dstSet = vk_desc.sets[vk_desc.next_free++],
|
||||
}};
|
||||
vkUpdateDescriptorSets(vk_core.device, ARRAYSIZE(wds), wds, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
tex->vk.descriptor = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
g_textures.stats.size_total += tex->total_size;
|
||||
g_textures.stats.count++;
|
||||
|
@ -1044,29 +1073,7 @@ finalize:
|
|||
return (tex - vk_textures);
|
||||
}
|
||||
|
||||
static int loadTextureUsingEngine( const char *name, const byte *buf, size_t size, int flags );
|
||||
|
||||
int VK_LoadTexture( const char *name, const byte *buf, size_t size, int flags )
|
||||
{
|
||||
if( !Common_CheckTexName( name ))
|
||||
return 0;
|
||||
|
||||
// see if already loaded
|
||||
vk_texture_t *tex = Common_TextureForName( name );
|
||||
if( tex )
|
||||
return (tex - vk_textures);
|
||||
|
||||
{
|
||||
const char *ext = Q_strrchr(name, '.');
|
||||
if (Q_strcmp(ext, ".ktx2") == 0) {
|
||||
return loadKtx2(name);
|
||||
}
|
||||
}
|
||||
|
||||
return loadTextureUsingEngine(name, buf, size, flags);
|
||||
}
|
||||
|
||||
static int loadTextureUsingEngine( const char *name, const byte *buf, size_t size, int flags ) {
|
||||
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 ))
|
||||
|
@ -1087,7 +1094,7 @@ static int loadTextureUsingEngine( const char *name, const byte *buf, size_t siz
|
|||
// upload texture
|
||||
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 ));
|
||||
gEngine.FS_FreeImage( pic ); // release source texture
|
||||
|
@ -1103,17 +1110,43 @@ static int loadTextureUsingEngine( const char *name, const byte *buf, size_t siz
|
|||
return tex - vk_textures;
|
||||
}
|
||||
|
||||
int XVK_LoadTextureReplace( const char *name, const byte *buf, size_t size, int flags ) {
|
||||
vk_texture_t *tex;
|
||||
static int loadTextureInternal( const char *name, const byte *buf, size_t size, int flags, colorspace_hint_e colorspace_hint ) {
|
||||
if( !Common_CheckTexName( name ))
|
||||
return 0;
|
||||
|
||||
// free if already loaded
|
||||
if(( tex = Common_TextureForName( name ))) {
|
||||
VK_FreeTexture( tex - vk_textures );
|
||||
// see if already loaded
|
||||
vk_texture_t *tex = Common_TextureForName( name );
|
||||
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 )
|
||||
|
@ -1182,7 +1215,7 @@ void VK_FreeTexture( unsigned int texnum ) {
|
|||
R_VkStagingFlushSync();
|
||||
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));
|
||||
|
@ -1222,7 +1255,7 @@ static int loadTextureFromBuffers( const char *name, rgbdata_t *const *const pic
|
|||
for (int i = 0; i < pic_count; ++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 ));
|
||||
return 0;
|
||||
|
@ -1250,7 +1283,7 @@ int XVK_TextureLookupF( const char *fmt, ...) {
|
|||
|
||||
static void unloadSkybox( void ) {
|
||||
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));
|
||||
|
@ -1348,7 +1381,7 @@ static qboolean loadSkybox( const char *prefix, int style ) {
|
|||
goto cleanup;
|
||||
|
||||
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:
|
||||
for (int j = 0; j < i; ++j)
|
||||
|
|
|
@ -16,8 +16,8 @@ typedef struct vk_texture_s
|
|||
uint texnum;
|
||||
|
||||
struct {
|
||||
xvk_image_t image;
|
||||
VkDescriptorSet descriptor;
|
||||
r_vk_image_t image;
|
||||
VkDescriptorSet descriptor_unorm;
|
||||
} vk;
|
||||
|
||||
uint hashValue;
|
||||
|
@ -48,6 +48,7 @@ typedef struct vk_textures_global_s
|
|||
vk_texture_t skybox_cube;
|
||||
vk_texture_t cubemap_placeholder;
|
||||
|
||||
// All textures descriptors in their native formats used for RT
|
||||
VkDescriptorImageInfo dii_all_textures[MAX_TEXTURES];
|
||||
|
||||
// FIXME this should not exist, all textures should have their own samplers based on flags
|
||||
|
@ -67,18 +68,24 @@ void initTextures( void );
|
|||
void destroyTextures( void );
|
||||
vk_texture_t *findTexture(int index);
|
||||
|
||||
typedef enum {
|
||||
kColorspaceNative,
|
||||
kColorspaceLinear,
|
||||
kColorspaceGamma,
|
||||
} colorspace_hint_e;
|
||||
|
||||
// Public API functions
|
||||
int VK_FindTexture( const char *name );
|
||||
const char* VK_TextureName( 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_LoadTextureArray( const char **names, int 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 );
|
||||
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, ...);
|
||||
|
||||
|
|
Loading…
Reference in New Issue