neurotic optimizations (overhauled depth pyramid and bloom to ffx-sdp), more fixes

This commit is contained in:
ecker 2026-04-21 20:49:47 -05:00
parent fd9036ee39
commit 6d05ab865a
27 changed files with 3986 additions and 434 deletions

View File

@ -110,7 +110,7 @@
"default stage buffers": true, "default stage buffers": true,
"default defer buffer destroy": true, "default defer buffer destroy": true,
"default command buffer immediate": true, "default command buffer immediate": true,
"multithreaded recording": true "multithreaded recording": false
}, },
"pipelines": { "pipelines": {
"deferred": true, "deferred": true,
@ -147,7 +147,8 @@
"deviceCoherentMemory", "deviceCoherentMemory",
"robustBufferAccess", "robustBufferAccess",
"samplerAnisotropy", "samplerAnisotropy",
"sampleRateShading" "sampleRateShading",
"samplerFilterMinmax"
], ],
"featureChain": [] "featureChain": []
}, },

View File

@ -1,9 +1,9 @@
{ {
// "import": "./rp_downtown_v2.json" // "import": "./rp_downtown_v2.json"
"import": "./ss2_medsci1.json" // "import": "./ss2_medsci1.json"
// "import": "./test_grid.json" // "import": "./test_grid.json"
// "import": "./sh2_mcdonalds.json" // "import": "./sh2_mcdonalds.json"
// "import": "./animal_crossing.json" // "import": "./animal_crossing.json"
// "import": "./mds_mcdonalds.json" "import": "./mds_mcdonalds.json"
// "import": "./gm_construct.json" // "import": "./gm_construct.json"
} }

View File

@ -44,6 +44,7 @@ void gammaCorrect( inout vec3 color, float gamma ) {
} }
void toneMap( inout vec4 color, float exposure ) { toneMap(color.rgb, exposure); } void toneMap( inout vec4 color, float exposure ) { toneMap(color.rgb, exposure); }
void gammaCorrect( inout vec4 color, float gamma ) { gammaCorrect(color.rgb, gamma); } void gammaCorrect( inout vec4 color, float gamma ) { gammaCorrect(color.rgb, gamma); }
float luma( vec3 color ) { return dot(color, vec3(0.2126, 0.7152, 0.0722)); }
// //
uint tea(uint val0, uint val1) { uint tea(uint val0, uint val1) {
uint v0 = val0; uint v0 = val0;
@ -152,6 +153,7 @@ vec3 decodeSrgb(vec3 rgb) {
const vec3 c = step(vec3(0.04045), rgb); const vec3 c = step(vec3(0.04045), rgb);
return mix(a, b, c); return mix(a, b, c);
} }
#if !SPD && (DEFERRED || FRAGMENT || COMPUTE || RT)
bool validTextureIndex( int textureIndex ) { bool validTextureIndex( int textureIndex ) {
return 0 <= textureIndex && textureIndex < MAX_TEXTURES; return 0 <= textureIndex && textureIndex < MAX_TEXTURES;
} }
@ -160,7 +162,6 @@ bool validCubemapIndex( int textureIndex ) {
return 0 <= textureIndex && textureIndex < MAX_CUBEMAPS; return 0 <= textureIndex && textureIndex < MAX_CUBEMAPS;
} }
#endif #endif
#if !BLOOM && (DEFERRED || FRAGMENT || COMPUTE || RT)
bool validTextureIndex( uint id ) { bool validTextureIndex( uint id ) {
return 0 <= id && id < MAX_TEXTURES; return 0 <= id && id < MAX_TEXTURES;
} }

View File

@ -1,65 +0,0 @@
#version 450
#pragma shader_stage(compute)
#define COMPUTE 1
#define TEXTURES 0
#define CUBEMAPS 0
#define BLOOM 1
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout( push_constant ) uniform PushBlock {
uint eye;
uint mode;
} PushConstant;
layout (binding = 0) uniform UBO {
float threshold;
float smoothness;
uint size;
float padding1;
float weights[32];
} ubo;
layout (binding = 1, rgba16f) uniform image2D imageColor;
layout (binding = 2, rgba16f) uniform image2D imageBloom;
layout (binding = 3, rgba16f) uniform image2D imagePingPong;
#include "../../common/macros.h"
#include "../../common/structs.h"
#include "../../common/functions.h"
void main() {
const uint mode = PushConstant.mode;
const ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
const ivec2 size = imageSize( imageColor );
if ( texel.x >= size.x || texel.y >= size.y ) return;
if ( mode == 0 ) { // fill bloom
vec3 result = imageLoad( imageColor, texel ).rgb;
float brightness = dot(result, vec3(0.2126, 0.7152, 0.0722));
if( brightness < ubo.threshold ) result = vec3(0.0);
imageStore(imageBloom, texel, vec4(result, 1.0));
} else if ( mode == 1 ) { // bloom horizontal
vec3 result = imageLoad( imageBloom, texel ).rgb * ubo.weights[0];
for ( int i = 1; i < int(ubo.size); ++i ) {
vec3 c1 = imageLoad( imageBloom, texel + ivec2(i, 0) ).rgb;
vec3 c2 = imageLoad( imageBloom, texel - ivec2(i, 0) ).rgb;
result += (c1 + c2) * ubo.weights[i];
}
imageStore( imagePingPong, texel, vec4(result, 1.0) );
} else if ( mode == 2 ) { // bloom vertical
vec3 result = imageLoad( imagePingPong, texel ).rgb * ubo.weights[0];
for( int i = 1; i < int(ubo.size); ++i ) {
vec3 c1 = imageLoad( imagePingPong, texel + ivec2(0, i) ).rgb;
vec3 c2 = imageLoad( imagePingPong, texel - ivec2(0, i) ).rgb;
result += (c1 + c2) * ubo.weights[i];
}
imageStore(imageBloom, texel, vec4(result, 1.0));
} else if ( mode == 3 ) { // combine
vec3 base = imageLoad( imageColor, texel ).rgb;
vec3 bloom = imageLoad( imageBloom, texel ).rgb;
imageStore( imageColor, texel, vec4(base + bloom, 1.0) );
}
}

View File

@ -0,0 +1,131 @@
#version 450
#pragma shader_stage(compute)
#extension GL_KHR_shader_subgroup_quad : require
#extension GL_KHR_shader_subgroup_arithmetic : require
#extension GL_EXT_samplerless_texture_functions : enable
#define COMPUTE 1
#define SPD 1
#include "../../common/macros.h"
#include "../../common/structs.h"
#include "../../common/functions.h"
layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in;
layout (constant_id = 0) const uint MIPS = 6;
layout(push_constant) uniform PushBlock {
uint mips;
uint numWorkGroups;
uint workGroupOffset;
} PushConstant_;
layout (binding = 0, rgba16f) uniform image2D imageColor;
layout (binding = 1, rgba16f) uniform image2D imageBright; // yucky
layout (binding = 2, rgba16f) coherent uniform image2D outImage[MIPS];
layout (binding = 3, std430) buffer AtomicCounter {
uint counter;
} spdCounter;
layout (binding = 4) uniform UBO {
float threshold;
float smoothness;
uint size;
float padding1;
float weights[32];
} ubo;
#define A_GLSL 1
#define A_GPU 1
#define SPD_NO_WAVE_OPERATIONS 0
#include "../../ext/ffx_a.h"
shared AU1 spd_counter;
shared AF4 spd_intermediate[16][16];
vec3 applySoftKnee(vec3 color, float luminance) {
float rq = clamp(luminance - ubo.threshold + ubo.smoothness, 0.0, 2.0 * ubo.smoothness);
rq = (rq * rq) / (4.0 * ubo.smoothness + 0.0001);
float value = max(rq, luminance - ubo.threshold);
return color * (value / (max(luminance, 0.0001)));
}
AF4 SpdLoadSourceImage(ASU2 p, AU1 slice) {
ivec2 size = imageSize(imageColor);
// sample color if in bound, else black
vec3 c0 = p.x < size.x && p.y < size.y ? imageLoad(imageColor, p + ivec2(0, 0)).rgb : vec3(0.0);
vec3 c1 = p.x + 1 < size.x && p.y < size.y ? imageLoad(imageColor, p + ivec2(1, 0)).rgb : vec3(0.0);
vec3 c2 = p.x < size.x && p.y + 1 < size.y ? imageLoad(imageColor, p + ivec2(0, 1)).rgb : vec3(0.0);
vec3 c3 = p.x + 1 < size.x && p.y + 1 < size.y ? imageLoad(imageColor, p + ivec2(1, 1)).rgb : vec3(0.0);
// get luma
float b0 = luma(c0);
float b1 = luma(c1);
float b2 = luma(c2);
float b3 = luma(c3);
// soften
c0 = applySoftKnee(c0, b0);
c1 = applySoftKnee(c1, b1);
c2 = applySoftKnee(c2, b2);
c3 = applySoftKnee(c3, b3);
// karis luma weighted average
float w0 = 1.0 / (b0 + 1.0);
float w1 = 1.0 / (b1 + 1.0);
float w2 = 1.0 / (b2 + 1.0);
float w3 = 1.0 / (b3 + 1.0);
float inv_wsum = 1.0 / (w0 + w1 + w2 + w3);
// store to mip 0
if (p.x < size.x && p.y < size.y) imageStore(outImage[0], p + ivec2(0, 0), vec4(c0, 1.0));
if (p.x + 1 < size.x && p.y < size.y) imageStore(outImage[0], p + ivec2(1, 0), vec4(c1, 1.0));
if (p.x < size.x && p.y + 1 < size.y) imageStore(outImage[0], p + ivec2(0, 1), vec4(c2, 1.0));
if (p.x + 1 < size.x && p.y + 1 < size.y) imageStore(outImage[0], p + ivec2(1, 1), vec4(c3, 1.0));
// average
return AF4((c0 * w0 + c1 * w1 + c2 * w2 + c3 * w3) * inv_wsum, 1.0);
}
AF4 SpdLoad(ASU2 p, AU1 slice) {
uint loadMip = min(6u - 1, MIPS - 1);
return imageLoad(outImage[loadMip + 1], p);
}
void SpdStore(ASU2 p, AF4 value, AU1 mip, AU1 slice) {
if ( mip + 1 < MIPS ) {
imageStore(outImage[mip + 1], p, value);
}
}
// average filter
AF4 SpdReduce4(AF4 v0, AF4 v1, AF4 v2, AF4 v3) {
return (v0 + v1 + v2 + v3) * 0.25;
}
AF4 SpdLoadIntermediate(AU1 x, AU1 y) { return spd_intermediate[x][y]; }
void SpdStoreIntermediate(AU1 x, AU1 y, AF4 value) { spd_intermediate[x][y] = value; }
void SpdIncreaseAtomicCounter(AU1 slice) { spd_counter = atomicAdd(spdCounter.counter, 1); }
AU1 SpdGetAtomicCounter() { return spd_counter; }
void SpdResetAtomicCounter(AU1 slice) { spdCounter.counter = 0; }
#include "../../ext/ffx_spd.h"
void main() {
SpdDownsample(
AU2(gl_WorkGroupID.xy),
AU1(gl_LocalInvocationIndex),
AU1(PushConstant_.mips - 1),
AU1(PushConstant_.numWorkGroups),
AU1(PushConstant_.workGroupOffset)
);
}

View File

@ -0,0 +1,60 @@
#version 450
#pragma shader_stage(compute)
#define COMPUTE 1
layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
layout (constant_id = 0) const uint MIPS = 6;
layout (binding = 0, rgba16f) uniform image2D imageColor;
layout (binding = 1) uniform sampler2D samplerBloom;
layout (binding = 2) uniform UBO {
float threshold;
float smoothness;
uint size;
float padding1;
float weights[32];
} ubo;
// 9-tap bilinear tent filter
vec3 tentFilter(sampler2D tex, vec2 uv, float lod) {
vec2 texSize = vec2(textureSize(tex, int(lod)));
vec4 d = (1.0 / texSize.xyxy) * vec4(1.0, 1.0, -1.0, 0.0);
vec3 s = textureLod(tex, uv - d.xy, lod).rgb;
s += textureLod(tex, uv - d.wy, lod).rgb * 2.0;
s += textureLod(tex, uv - d.zy, lod).rgb;
s += textureLod(tex, uv + d.zw, lod).rgb * 2.0;
s += textureLod(tex, uv, lod).rgb * 4.0;
s += textureLod(tex, uv + d.xw, lod).rgb * 2.0;
s += textureLod(tex, uv + d.zy, lod).rgb;
s += textureLod(tex, uv + d.wy, lod).rgb * 2.0;
s += textureLod(tex, uv + d.xy, lod).rgb;
return s * (1.0 / 16.0);
}
void main() {
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
ivec2 size = imageSize(imageColor);
if ( texel.x >= size.x || texel.y >= size.y ) return;
vec2 uv = (vec2(texel) + 0.5) / vec2(size);
vec3 bloomAcc = vec3(0.0);
float weightSum = 0.0;
for ( uint i = 0; i < min(MIPS, ubo.size); ++i ) {
float w = ubo.weights[i];
bloomAcc += textureLod(samplerBloom, uv, float(i)).rgb * w;
//bloomAcc += tentFilter(samplerBloom, uv, float(i)) * w;
weightSum += w;
}
if ( weightSum > 0.0 ) bloomAcc /= weightSum;
vec3 base = imageLoad( imageColor, texel ).rgb;
imageStore( imageColor, texel, vec4(base + bloomAcc, 1.0) );
}

View File

@ -159,7 +159,7 @@ void postProcess() {
#if FOG #if FOG
fog( surface.ray, surface.fragment.rgb, surface.fragment.a ); fog( surface.ray, surface.fragment.rgb, surface.fragment.a );
#endif #endif
float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); float brightness = luma(surface.fragment.rgb);
bool bloom = brightness > ubo.settings.bloom.threshold; bool bloom = brightness > ubo.settings.bloom.threshold;
//if ( bloom ) toneMap( surface.fragment.rgb, brightness ); //if ( bloom ) toneMap( surface.fragment.rgb, brightness );
vec4 outFragColor = vec4(surface.fragment.rgb, 1.0); vec4 outFragColor = vec4(surface.fragment.rgb, 1.0);
@ -184,7 +184,7 @@ void postProcess() {
} }
IMAGE_STORE( imageColor, outFragColor ); IMAGE_STORE( imageColor, outFragColor );
IMAGE_STORE( imageBright, outFragBright ); //IMAGE_STORE( imageBright, outFragBright );
IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) ); IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) );
} }

View File

@ -1,35 +1,96 @@
#version 450 #version 450
#pragma shader_stage(compute) #pragma shader_stage(compute)
//#extension GL_EXT_nonuniform_qualifier : enable #extension GL_KHR_shader_subgroup_quad : require
#extension GL_KHR_shader_subgroup_arithmetic : require
layout (constant_id = 0) const uint MIPS = 6; #extension GL_EXT_samplerless_texture_functions : enable
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#define COMPUTE 1 #define COMPUTE 1
#define SPD 1
#include "../../common/macros.h" #include "../../common/macros.h"
#include "../../common/structs.h" #include "../../common/structs.h"
#include "../../common/functions.h"
layout( push_constant ) uniform PushBlock { layout (local_size_x = 256, local_size_y = 1, local_size_z = 1) in;
uint _;
uint pass; layout (constant_id = 0) const uint MIPS = 6;
} PushConstant;
layout(push_constant) uniform PushBlock {
uint mips;
uint numWorkGroups;
uint workGroupOffset;
} PushConstant_;
layout (binding = 0) uniform sampler2D samplerDepth; layout (binding = 0) uniform sampler2D samplerDepth;
layout (binding = 1) uniform sampler2D inImage[MIPS]; layout (binding = 1, r32f) coherent uniform image2D outImage[MIPS];
layout (binding = 2, r32f) uniform writeonly image2D outImage[MIPS];
layout (binding = 2, std430) buffer AtomicCounter {
uint counter;
} spdCounter;
#define A_GLSL 1
#define A_GPU 1
#define SPD_NO_WAVE_OPERATIONS 0
#include "../../ext/ffx_a.h"
shared AU1 spd_counter;
shared AF1 spd_intermediate[16][16];
AF4 SpdLoadSourceImage(ASU2 p, AU1 slice) {
ivec2 size = imageSize(outImage[0]);
// sample depth if in bound, else 0 (0 for reverse-z projection, use 1 if normal projection)
float d0 = p.x < size.x && p.y < size.y ? texelFetch(samplerDepth, p + ivec2(0, 0), 0).x : 0.0;
float d1 = p.x + 1 < size.x && p.y < size.y ? texelFetch(samplerDepth, p + ivec2(1, 0), 0).x : 0.0;
float d2 = p.x < size.x && p.y + 1 < size.y ? texelFetch(samplerDepth, p + ivec2(0, 1), 0).x : 0.0;
float d3 = p.x + 1 < size.x && p.y + 1 < size.y ? texelFetch(samplerDepth, p + ivec2(1, 1), 0).x : 0.0;
// store to mip 0
if (p.x < size.x && p.y < size.y) imageStore(outImage[0], p + ivec2(0, 0), vec4(d0));
if (p.x + 1 < size.x && p.y < size.y) imageStore(outImage[0], p + ivec2(1, 0), vec4(d1));
if (p.x < size.x && p.y + 1 < size.y) imageStore(outImage[0], p + ivec2(0, 1), vec4(d2));
if (p.x + 1 < size.x && p.y + 1 < size.y) imageStore(outImage[0], p + ivec2(1, 1), vec4(d3));
return AF4(d0, d1, d2, d3);
}
AF4 SpdLoad(ASU2 p, AU1 slice) {
uint loadMip = min(6u, MIPS - 1);
float d = imageLoad(outImage[loadMip], p).r;
return AF4(d, d, d, d);
}
void SpdStore(ASU2 p, AF4 value, AU1 mip, AU1 slice) {
if ( mip + 1 < MIPS ) {
imageStore(outImage[mip + 1], p, vec4(value.x));
}
}
AF4 SpdLoadIntermediate(AU1 x, AU1 y) {
float d = spd_intermediate[x][y];
return AF4(d, d, d, d);
}
void SpdStoreIntermediate(AU1 x, AU1 y, AF4 value) { spd_intermediate[x][y] = value.x; }
void SpdIncreaseAtomicCounter(AU1 slice) { spd_counter = atomicAdd(spdCounter.counter, 1); }
AU1 SpdGetAtomicCounter() { return spd_counter; }
void SpdResetAtomicCounter(AU1 slice) { spdCounter.counter = 0; }
// min filter
AF4 SpdReduce4(AF4 v0, AF4 v1, AF4 v2, AF4 v3) {
float minVal = min(min(v0.x, v1.x), min(v2.x, v3.x));
return AF4(minVal, minVal, minVal, minVal);
}
#include "../../ext/ffx_spd.h"
void main() { void main() {
int mip = int(PushConstant.pass); SpdDownsample(
AU2(gl_WorkGroupID.xy),
float depth; AU1(gl_LocalInvocationIndex),
ivec2 pos = ivec2(gl_GlobalInvocationID.xy); AU1(PushConstant_.mips - 1),
if ( mip == 0 ) { AU1(PushConstant_.numWorkGroups),
depth = texelFetch(samplerDepth, pos, 0).r; AU1(PushConstant_.workGroupOffset)
} else { );
depth = texture(inImage[mip - 1], (vec2(gl_GlobalInvocationID.xy) + vec2(0.5)) / imageSize( outImage[mip] )).x;
}
imageStore(outImage[mip], pos, vec4(depth));
} }

1907
bin/data/shaders/ext/ffx_a.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
#extension GL_EXT_samplerless_texture_functions : enable #extension GL_EXT_samplerless_texture_functions : enable
layout (constant_id = 0) const uint PASSES = 6; layout (constant_id = 0) const uint PASSES = 6;
layout (local_size_x = 32, local_size_y = 1, local_size_z = 1) in; layout (local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
#define COMPUTE 1 #define COMPUTE 1
#define QUERY_MIPMAPS 1 #define QUERY_MIPMAPS 1
@ -73,106 +73,100 @@ layout (std140, binding = 3) buffer Objects {
layout (binding = 4) uniform sampler2D samplerDepth; layout (binding = 4) uniform sampler2D samplerDepth;
shared vec4 sharedPlanes[PASSES][6];
vec4 normalizePlane( vec4 p ) { vec4 normalizePlane( vec4 p ) {
return p / length(p.xyz); return p / length(p.xyz);
}
bool frustumCull( uint id ) {
if ( PushConstant.passes == 0 ) return true;
const DrawCommand drawCommand = drawCommands[id];
const Instance instance = instances[drawCommand.instanceID];
const Object object = objects[instance.objectID];
if ( drawCommand.indices == 0 || drawCommand.vertices == 0 ) return false;
bool visible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * object.model;
vec4 planes[6]; {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
planes[i*2+j] = normalizePlane( planes[i*2+j] );
}
}
bool insideFrustum = true;
for ( uint p = 0; p < 6; ++p ) {
float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x)
+ max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y)
+ max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z);
if (d < -planes[p].w) {
insideFrustum = false;
break;
}
}
if ( insideFrustum ) {
visible = true;
break;
}
}
return visible;
}
bool occlusionCull( uint id ) {
if ( PushConstant.passes == 0 ) return true;
const DrawCommand drawCommand = drawCommands[id];
const Instance instance = instances[drawCommand.instanceID];
const Object object = objects[instance.objectID];
bool visible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
vec4 aabb;
vec4 sphere = aabbToSphere( instance.bounds );
float scale = length(object.model[0].xyz);
vec3 center = (camera.viewport[pass].view * object.model * vec4(sphere.xyz, 1)).xyz;
float radius = scale * sphere.w;
mat4 proj = camera.viewport[pass].projection;
float znear = proj[3][2];
float P00 = proj[0][0];
float P11 = proj[1][1];
if ( projectSphere( center, radius, znear, P00, P11, aabb ) ) {
vec2 pyramidSize = vec2(textureSize( samplerDepth, 0 ));
float width = (aabb.z - aabb.x) * pyramidSize.x;
float height = (aabb.w - aabb.y) * pyramidSize.y;
float level = max(0.0, floor(log2(max(width, height))));
float d1 = textureLod(samplerDepth, vec2(aabb.x, aabb.y), level).x;
float d2 = textureLod(samplerDepth, vec2(aabb.z, aabb.y), level).x;
float d3 = textureLod(samplerDepth, vec2(aabb.x, aabb.w), level).x;
float d4 = textureLod(samplerDepth, vec2(aabb.z, aabb.w), level).x;
float depth = min(min(d1, d2), min(d3, d4)); // min for reverse-z projection, max for standard
float depthSphere = znear / (center.z - radius);
if ( depthSphere >= depth - DEPTH_BIAS ) {
visible = true;
break;
}
} else {
visible = true;
break;
}
}
return visible;
} }
void main() { void main() {
const uint gID = gl_GlobalInvocationID.x; const uint gID = gl_GlobalInvocationID.x;
if ( !(0 <= gID && gID < drawCommands.length()) ) return; const uint lID = gl_LocalInvocationIndex;
bool visible = frustumCull( gID ); if ( lID == 0 ) {
if ( visible ) visible = occlusionCull( gID ); for (uint pass = 0; pass < PushConstant.passes; ++pass) {
drawCommands[gID].instances = visible ? 1 : 0; mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
sharedPlanes[pass][i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
sharedPlanes[pass][i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
sharedPlanes[pass][i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
sharedPlanes[pass][i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
sharedPlanes[pass][i*2+j] = normalizePlane( sharedPlanes[pass][i*2+j] );
}
}
}
barrier();
if ( gID >= drawCommands.length() ) return;
const DrawCommand drawCommand = drawCommands[gID];
if ( drawCommand.indices == 0 || drawCommand.vertices == 0 ) return;
const Instance instance = instances[drawCommand.instanceID];
const Object object = objects[instance.objectID];
vec4 sphere = aabbToSphere( instance.bounds );
vec3 worldCenter = (object.model * vec4(sphere.xyz, 1.0)).xyz;
float scaleX = length(object.model[0].xyz);
float scaleY = length(object.model[1].xyz);
float scaleZ = length(object.model[2].xyz);
float maxScale = max(max(scaleX, scaleY), scaleZ);
float worldRadius = sphere.w * maxScale;
bool isVisible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
bool insideFrustum = true;
for ( int p = 0; p < 6; ++p ) {
if ( dot(sharedPlanes[pass][p].xyz, worldCenter) + sharedPlanes[pass][p].w < -worldRadius ) {
insideFrustum = false;
break;
}
}
if ( insideFrustum ) {
isVisible = true;
break;
}
}
if ( isVisible ) {
isVisible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
vec4 aabb;
vec3 viewCenter = ( camera.viewport[pass].view * vec4(worldCenter, 1.0) ).xyz;
mat4 proj = camera.viewport[pass].projection;
float znear = proj[3][2];
float P00 = proj[0][0];
float P11 = proj[1][1];
if ( projectSphere(viewCenter, worldRadius, znear, P00, P11, aabb) ) {
vec2 pyramidSize = vec2(textureSize( samplerDepth, 0 ));
float width = (aabb.z - aabb.x) * pyramidSize.x;
float height = (aabb.w - aabb.y) * pyramidSize.y;
float level = floor(log2(max(width, height)));
level = max(0.0, level);
float d1 = textureLod(samplerDepth, vec2(aabb.x, aabb.y), level).x;
float d2 = textureLod(samplerDepth, vec2(aabb.z, aabb.y), level).x;
float d3 = textureLod(samplerDepth, vec2(aabb.x, aabb.w), level).x;
float d4 = textureLod(samplerDepth, vec2(aabb.z, aabb.w), level).x;
float depth = min(min(d1, d2), min(d3, d4));
float depthSphere = znear / (viewCenter.z - worldRadius);
if ( depthSphere >= depth - DEPTH_BIAS ) {
isVisible = true;
break;
}
} else {
isVisible = true;
break;
}
}
}
drawCommands[gID].instances = isVisible ? 1 : 0;
} }

View File

@ -390,7 +390,7 @@ void main() {
#endif #endif
{ {
#if BLOOM #if BLOOM
float brightness = dot(surface.fragment.rgb, vec3(0.2126, 0.7152, 0.0722)); float brightness = luma(surface.fragment.rgb);
vec4 outFragBright = brightness > ubo.threshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1); vec4 outFragBright = brightness > ubo.threshold ? vec4(surface.fragment.rgb, 1.0) : vec4(0, 0, 0, 1);
// imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFragBright); // imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFragBright);
#endif #endif

View File

@ -111,6 +111,8 @@ namespace pod {
uf::renderer::Buffer material; uf::renderer::Buffer material;
uf::renderer::Buffer texture; uf::renderer::Buffer texture;
uf::renderer::Buffer light; uf::renderer::Buffer light;
uf::renderer::Texture2D depthPyramid;
} buffers; } buffers;
}/* storage*/; }/* storage*/;
}; };

View File

@ -28,6 +28,8 @@ namespace ext {
operator VkCommandBuffer() { return handle; } operator VkCommandBuffer() { return handle; }
}; };
struct Texture;
struct UF_API Device { struct UF_API Device {
VkInstance instance; VkInstance instance;
VkDebugUtilsMessengerEXT debugMessenger; VkDebugUtilsMessengerEXT debugMessenger;
@ -86,6 +88,7 @@ namespace ext {
uf::stl::vector<Buffer> buffers; uf::stl::vector<Buffer> buffers;
uf::stl::vector<AccelerationStructure> ass; uf::stl::vector<AccelerationStructure> ass;
uf::stl::vector<Texture> textures;
} transient; } transient;
struct { struct {

View File

@ -42,8 +42,8 @@ namespace ext {
void record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer, size_t = 0, size_t = 0, size_t = 0 ) const; void record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer, size_t = 0, size_t = 0, size_t = 0 ) const;
void destroy(); void destroy();
uf::stl::vector<Shader*> getShaders( uf::stl::vector<Shader>& ); uf::stl::vector<Shader*> getShaders( uf::stl::vector<Shader>&, const uf::stl::string& = "" );
uf::stl::vector<const Shader*> getShaders( const uf::stl::vector<Shader>& ) const; uf::stl::vector<const Shader*> getShaders( const uf::stl::vector<Shader>&, const uf::stl::string& = "" ) const;
void collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const; void collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const;
}; };

View File

@ -138,7 +138,7 @@ namespace ext {
inline void update( uf::Image& image, uint32_t layer = 1 ) { return this->update(image, this->imageLayout, layer); } inline void update( uf::Image& image, uint32_t layer = 1 ) { return this->update(image, this->imageLayout, layer); }
inline void update( void* data, VkDeviceSize size, uint32_t layer = 1 ) { return this->update(data, size, this->imageLayout, layer); } inline void update( void* data, VkDeviceSize size, uint32_t layer = 1 ) { return this->update(data, size, this->imageLayout, layer); }
void generateMipmaps(VkCommandBuffer commandBuffer, uint32_t layer = 1); void generateMipmaps(VkCommandBuffer commandBuffer, uint32_t layer = 0);
void fromBuffers( void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, uint32_t texDepth, uint32_t layers, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ); void fromBuffers( void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, uint32_t texDepth, uint32_t layers, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL );
inline void fromBuffers( void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) { return this->fromBuffers(buffer, bufferSize, format, texWidth, texHeight, 1, 1, imageUsageFlags, imageLayout); } inline void fromBuffers( void* buffer, VkDeviceSize bufferSize, VkFormat format, uint32_t texWidth, uint32_t texHeight, VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) { return this->fromBuffers(buffer, bufferSize, format, texWidth, texHeight, 1, 1, imageUsageFlags, imageLayout); }

View File

@ -22,7 +22,7 @@
#define VK_DEFAULT_STAGE_BUFFERS ext::vulkan::settings::defaultStageBuffers #define VK_DEFAULT_STAGE_BUFFERS ext::vulkan::settings::defaultStageBuffers
#define VK_DEFAULT_DEFER_BUFFER_DESTROY ext::vulkan::settings::defaultDeferBufferDestroy #define VK_DEFAULT_DEFER_BUFFER_DESTROY ext::vulkan::settings::defaultDeferBufferDestroy
#define VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ext::vulkan::settings::defaultCommandBufferImmediate #define VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ext::vulkan::settings::defaultCommandBufferImmediate
#define VK_UBO_USE_N_BUFFERS 1 #define VK_UBO_USE_N_BUFFERS 0
namespace ext { namespace ext {
namespace vulkan { namespace vulkan {

View File

@ -182,10 +182,6 @@ namespace ext {
extern UF_API uint32_t frameSkip; extern UF_API uint32_t frameSkip;
} }
namespace gc {
extern UF_API uf::stl::vector<ext::vulkan::Texture> textures;
}
extern UF_API Device device; extern UF_API Device device;
extern UF_API Allocator allocator; extern UF_API Allocator allocator;

View File

@ -938,8 +938,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
#if UF_USE_VULKAN #if UF_USE_VULKAN
// only update this when requested // only update this when requested
// done outside of deserialize because the rendermode might not be initialized in time // done outside of deserialize because the rendermode might not be initialized in time
if ( uf::renderer::settings::pipelines::bloom && metadata.bloom.outOfDate && graphic.material.hasShader("compute", "bloom") ) { if ( uf::renderer::settings::pipelines::bloom && metadata.bloom.outOfDate && graphic.material.hasShader("compute", "bloom-down") ) {
auto& shader = graphic.material.getShader("compute", "bloom"); auto& shaderDown = graphic.material.getShader("compute", "bloom-down");
auto& shaderUp = graphic.material.getShader("compute", "bloom-up");
struct UniformDescriptor { struct UniformDescriptor {
float threshold; float threshold;
@ -974,7 +975,12 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
for ( auto i = 0; i < uniforms.size; ++i ) uniforms.weights[i] = tempWeights[i] / sum; for ( auto i = 0; i < uniforms.size; ++i ) uniforms.weights[i] = tempWeights[i] / sum;
metadata.bloom.outOfDate = false; metadata.bloom.outOfDate = false;
if ( shader.hasUniform("UBO") ) shader.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shader.getUniformBuffer("UBO") ); if ( shaderDown.hasUniform("UBO") ) {
shaderDown.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shaderDown.getUniformBuffer("UBO") );
}
if ( shaderUp.hasUniform("UBO") ) {
shaderUp.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shaderUp.getUniformBuffer("UBO") );
}
} }
struct UniformDescriptor { struct UniformDescriptor {

View File

@ -196,7 +196,6 @@ namespace {
// compute shader // compute shader
auto& shader = graphic.material.getShader("compute", uf::renderer::settings::pipelines::names::culling); auto& shader = graphic.material.getShader("compute", uf::renderer::settings::pipelines::names::culling);
shader.aliasAttachment("depthPyramid");
} }
// vxgi pipeline // vxgi pipeline
if ( uf::renderer::settings::pipelines::vxgi ) { if ( uf::renderer::settings::pipelines::vxgi ) {
@ -479,6 +478,9 @@ namespace {
shader.aliasBuffer( "indirect", *indirect ); shader.aliasBuffer( "indirect", *indirect );
shader.aliasBuffer( "instance", storage.buffers.instance ); shader.aliasBuffer( "instance", storage.buffers.instance );
shader.aliasBuffer( "object", storage.buffers.object ); shader.aliasBuffer( "object", storage.buffers.object );
shader.textures.clear();
shader.textures.emplace_back().aliasTexture( storage.buffers.depthPyramid );
} }
// vxgi pipeline // vxgi pipeline
@ -1532,10 +1534,12 @@ void uf::graph::destroy( uf::Object& object, bool soft ) {
void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) { void uf::graph::destroy( pod::Graph::Storage& storage, bool soft ) {
soft = false; soft = false;
#if UF_USE_VULKAN #if UF_USE_VULKAN
/*
for ( auto& texture : uf::renderer::gc::textures ) { for ( auto& texture : uf::renderer::gc::textures ) {
texture.destroy( false ); texture.destroy( false );
} }
uf::renderer::gc::textures.clear(); uf::renderer::gc::textures.clear();
*/
#endif #endif
// cleanup graphic handles // cleanup graphic handles

View File

@ -41,7 +41,7 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
this->metadata.type = descriptor.pipeline; this->metadata.type = descriptor.pipeline;
Device& device = *graphic.device; Device& device = *graphic.device;
auto shaders = getShaders( graphic.material.shaders ); auto shaders = getShaders( graphic.material.shaders, descriptor.pipeline );
assert( shaders.size() > 0 ); assert( shaders.size() > 0 );
uint32_t subpass = descriptor.subpass; uint32_t subpass = descriptor.subpass;
@ -397,7 +397,10 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer comm
return record( graphic, descriptor, commandBuffer, pass, draw, offset ); return record( graphic, descriptor, commandBuffer, pass, draw, offset );
} }
void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const { void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
auto shaders = getShaders( graphic.material.shaders ); auto shaders = getShaders( graphic.material.shaders, descriptor.pipeline );
for ( auto i = 0; i < shaders.size(); ++i ) {
// UF_MSG_DEBUG("{} | {}: {}", descriptor.pipeline, i, shaders[i]->filename);
}
// create dynamic offset ranges // create dynamic offset ranges
static thread_local uf::stl::vector<uint32_t> dynamicOffsets; static thread_local uf::stl::vector<uint32_t> dynamicOffsets;
@ -427,6 +430,7 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
else continue; else continue;
} }
// automatically bind to our default push constants
if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) { if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) {
struct PushConstant { struct PushConstant {
uint32_t pass; uint32_t pass;
@ -450,7 +454,10 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
} }
// no matching bind point for shaders, skip // no matching bind point for shaders, skip
if ( !bound ) return; if ( !bound ) {
UF_MSG_DEBUG("No shaders found to bind...");
return;
}
// Bind descriptor sets describing shader binding points // Bind descriptor sets describing shader binding points
#if VK_UBO_USE_N_BUFFERS #if VK_UBO_USE_N_BUFFERS
@ -506,7 +513,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true); RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true);
auto& renderTarget = renderMode.getRenderTarget(/*descriptor.renderTarget*/); auto& renderTarget = renderMode.getRenderTarget(/*descriptor.renderTarget*/);
auto shaders = getShaders( graphic.material.shaders ); auto shaders = getShaders( graphic.material.shaders, descriptor.pipeline );
uf::stl::vector<VkWriteDescriptorSet> writeDescriptorSets; uf::stl::vector<VkWriteDescriptorSet> writeDescriptorSets;
uf::stl::vector<uf::renderer::AccelerationStructure> tlases; uf::stl::vector<uf::renderer::AccelerationStructure> tlases;
@ -947,32 +954,32 @@ void ext::vulkan::Pipeline::destroy() {
} }
*/ */
} }
uf::stl::vector<ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( uf::stl::vector<ext::vulkan::Shader>& shaders ) { uf::stl::vector<ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( uf::stl::vector<ext::vulkan::Shader>& shaders, const uf::stl::string& type ) {
uf::stl::unordered_map<uf::stl::string, ext::vulkan::Shader*> map; uf::stl::unordered_map<uf::stl::string, ext::vulkan::Shader*> map;
uf::stl::vector<ext::vulkan::Shader*> res; uf::stl::vector<ext::vulkan::Shader*> res;
bool isCompute = false; bool isCompute = false;
for ( auto& shader : shaders ) { for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != (type == "" ? metadata.type : type) ) continue;
if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true; if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true;
} }
for ( auto& shader : shaders ) { for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != (type == "" ? metadata.type : type) ) continue;
if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
map[shader.metadata.type] = &shader; map[shader.metadata.type] = &shader;
} }
for ( auto pair : map ) res.insert( res.begin(), pair.second); for ( auto pair : map ) res.insert( res.begin(), pair.second);
return res; return res;
} }
uf::stl::vector<const ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( const uf::stl::vector<ext::vulkan::Shader>& shaders ) const { uf::stl::vector<const ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( const uf::stl::vector<ext::vulkan::Shader>& shaders, const uf::stl::string& type ) const {
uf::stl::unordered_map<uf::stl::string, const ext::vulkan::Shader*> map; uf::stl::unordered_map<uf::stl::string, const ext::vulkan::Shader*> map;
uf::stl::vector<const ext::vulkan::Shader*> res; uf::stl::vector<const ext::vulkan::Shader*> res;
bool isCompute = false; bool isCompute = false;
for ( auto& shader : shaders ) { for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != (type == "" ? metadata.type : type) ) continue;
if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true; if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) isCompute = true;
} }
for ( auto& shader : shaders ) { for ( auto& shader : shaders ) {
if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != metadata.type ) continue; if ( shader.metadata.pipeline != "" && shader.metadata.pipeline != (type == "" ? metadata.type : type) ) continue;
if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue; if ( isCompute && shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
map[shader.metadata.type] = &shader; map[shader.metadata.type] = &shader;
} }
@ -1839,19 +1846,19 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, size_t pass, s
void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass, size_t draw, size_t offset ) const { void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass, size_t draw, size_t offset ) const {
if ( !process ) return; if ( !process ) return;
if ( !this->hasPipeline( descriptor ) ) { if ( !this->hasPipeline( descriptor ) ) {
VK_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline ({} {})", descriptor.renderMode, descriptor.renderTarget); //UF_MSG_DEBUG("{} has no valid pipeline ({}:{}:{})", (void*) this, descriptor.renderMode, descriptor.renderTarget, descriptor.pipeline);
return; return;
} }
auto& pipeline = this->getPipeline( descriptor ); auto& pipeline = this->getPipeline( descriptor );
if ( pipeline.descriptorSet == VK_NULL_HANDLE ) { if ( pipeline.descriptorSet == VK_NULL_HANDLE ) {
VK_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline descriptor set ({} {})", descriptor.renderMode, descriptor.renderTarget); //UF_MSG_DEBUG("{} has no valid pipeline descriptor set ({}:{}:{})", (void*) this, descriptor.renderMode, descriptor.renderTarget, descriptor.pipeline);
return; return;
} }
if ( !pipeline.metadata.process ) return; if ( !pipeline.metadata.process ) return;
pipeline.record(*this, descriptor, commandBuffer, pass, draw, offset); pipeline.record(*this, descriptor, commandBuffer, pass, draw, offset);
auto shaders = pipeline.getShaders( material.shaders ); auto shaders = pipeline.getShaders( material.shaders, descriptor.pipeline );
for ( auto* shader : shaders ) { for ( auto* shader : shaders ) {
if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return; if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return;
if ( if (

View File

@ -273,8 +273,8 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
// swapchain.destroy(); // swapchain.destroy();
swapchain.initialize( device ); swapchain.initialize( device );
// bind swapchain images // bind swapchain images
images.resize( ext::vulkan::swapchain.buffers ); ::images.resize( ext::vulkan::swapchain.buffers );
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device, swapchain.swapChain, &swapchain.buffers, images.data())); VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device, swapchain.swapChain, &swapchain.buffers, ::images.data()));
// create image views for swapchain images // create image views for swapchain images
renderTarget.attachments.clear(); renderTarget.attachments.clear();
@ -302,7 +302,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
colorAttachmentView.subresourceRange.layerCount = 1; colorAttachmentView.subresourceRange.layerCount = 1;
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D; colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
colorAttachmentView.flags = 0; colorAttachmentView.flags = 0;
colorAttachmentView.image = images[frame]; colorAttachmentView.image = ::images[frame];
VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[frame].view)); VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[frame].view));
VK_REGISTER_HANDLE( renderTarget.attachments[frame].view ); VK_REGISTER_HANDLE( renderTarget.attachments[frame].view );
@ -312,7 +312,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
renderTarget.attachments[frame].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; renderTarget.attachments[frame].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
renderTarget.attachments[frame].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; renderTarget.attachments[frame].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
renderTarget.attachments[frame].descriptor.aliased = true; renderTarget.attachments[frame].descriptor.aliased = true;
renderTarget.attachments[frame].image = images[frame]; renderTarget.attachments[frame].image = ::images[frame];
renderTarget.attachments[frame].mem = VK_NULL_HANDLE; renderTarget.attachments[frame].mem = VK_NULL_HANDLE;
metadata.attachments["color["+std::to_string((int) frame)+"]"] = attachmentIndex++; metadata.attachments["color["+std::to_string((int) frame)+"]"] = attachmentIndex++;
@ -530,7 +530,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
// Create framebuffer // Create framebuffer
{ {
// Create a frame buffer for every image in the swapchain // Create a frame buffer for every image in the swapchain
renderTarget.framebuffers.resize(images.size()); renderTarget.framebuffers.resize(::images.size());
for (size_t frame = 0; frame < renderTarget.framebuffers.size(); frame++) for (size_t frame = 0; frame < renderTarget.framebuffers.size(); frame++)
{ {
std::array<VkImageView, 2> attachments; std::array<VkImageView, 2> attachments;
@ -555,7 +555,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
#if 0 #if 0
if ( true ) { if ( true ) {
auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::TRANSFER); auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::TRANSFER);
for ( size_t frame = 0; frame < images.size(); ++frame ) { for ( size_t frame = 0; frame < ::images.size(); ++frame ) {
VkImageMemoryBarrier imageMemoryBarrier = {}; VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.srcAccessMask = 0; imageMemoryBarrier.srcAccessMask = 0;
@ -652,10 +652,11 @@ void ext::vulkan::BaseRenderMode::destroy() {
} }
for ( auto& image : ::images ) { for ( auto& image : ::images ) {
// vkDestroyImage( *device, image, nullptr ); // vkDestroyImage( *device, image, nullptr ); // destroyed via vkDestroySwapchainKHR
VK_UNREGISTER_HANDLE( image ); VK_UNREGISTER_HANDLE( image );
image = VK_NULL_HANDLE; image = VK_NULL_HANDLE;
} }
::images.clear();
ext::vulkan::RenderMode::destroy(); ext::vulkan::RenderMode::destroy();

View File

@ -26,22 +26,34 @@
namespace { namespace {
const uf::stl::string DEFERRED_MODE = "compute"; const uf::stl::string DEFERRED_MODE = "compute";
ext::vulkan::Texture depthPyramid;
uf::stl::vector<VkImageView> depthPyramidViews; uf::stl::vector<VkImageView> depthPyramidViews;
uf::stl::vector<VkImageView> bloomViews;
void cmdImageBarrier(VkCommandBuffer commandBuffer, VkImage image, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkImageLayout oldLayout, VkImageLayout newLayout) { ext::vulkan::Buffer atomicCounterBloom;
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; ext::vulkan::Buffer atomicCounterDepth;
barrier.srcAccessMask = srcAccess;
barrier.dstAccessMask = dstAccess;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = image;
barrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); struct AtomicCounter {
uint32_t counter;
}; };
struct PushConstants {
uint32_t mips;
uint32_t numWorkGroups;
uint32_t workGroupOffset;
};
void destroyImageView( ext::vulkan::RenderMode* self, VkImageView view ) {
ext::vulkan::mutex.lock();
auto& texture = self->device->transient.textures.emplace_back();
ext::vulkan::mutex.unlock();
texture.device = self->device;
texture.view = view;
/*
vkDestroyImageView(self->device.logicalDevice, view, nullptr);
VK_UNREGISTER_HANDLE(view);
*/
}
} }
#include "./transition.inl" #include "./transition.inl"
@ -64,8 +76,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
struct { struct {
size_t id, bary, depth, uv, normal; size_t id, bary, depth, uv, normal;
size_t color, bright, motion, scratch, output; size_t color, bright, motion, output;
size_t depthPyramid;
} attachments = {}; } attachments = {};
bool blend = true; // !ext::vulkan::settings::invariant::deferredSampling; bool blend = true; // !ext::vulkan::settings::invariant::deferredSampling;
@ -108,7 +119,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{ attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format = */ext::vulkan::settings::formats::depth, /*.format = */ext::vulkan::settings::formats::depth,
/*.layout = */VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, /*.layout = */VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, /*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
/*.blend = */false, /*.blend = */false,
/*.samples = */msaa, /*.samples = */msaa,
//*.mips = */1, //*.mips = */1,
@ -127,13 +138,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.blend =*/ blend, /*.blend =*/ blend,
/*.samples =*/ 1, /*.samples =*/ 1,
}); /*.mips =*/ mips,
attachments.scratch = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.blend =*/ blend,
/*.samples =*/ 1,
}); });
attachments.motion = renderTarget.attach(RenderTarget::Attachment::Descriptor{ attachments.motion = renderTarget.attach(RenderTarget::Attachment::Descriptor{
// /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT, // /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT,
@ -143,14 +148,6 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.blend = */false, /*.blend = */false,
/*.samples = */1, /*.samples = */1,
}); });
attachments.depthPyramid = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format = */VK_FORMAT_R32_SFLOAT,
/*.layout = */ VK_IMAGE_LAYOUT_GENERAL,
/*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.blend = */false,
/*.samples = */1,
/*.mips = */mips,
});
metadata.attachments["id"] = attachments.id; metadata.attachments["id"] = attachments.id;
@ -164,10 +161,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
#endif #endif
metadata.attachments["depth"] = attachments.depth; metadata.attachments["depth"] = attachments.depth;
metadata.attachments["depthPyramid"] = attachments.depthPyramid;
metadata.attachments["color"] = attachments.color; metadata.attachments["color"] = attachments.color;
metadata.attachments["bright"] = attachments.bright; metadata.attachments["bright"] = attachments.bright;
metadata.attachments["scratch"] = attachments.scratch;
metadata.attachments["motion"] = attachments.motion; metadata.attachments["motion"] = attachments.motion;
metadata.attachments["output"] = attachments.color; metadata.attachments["output"] = attachments.color;
@ -339,13 +334,67 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
} }
if ( settings::pipelines::bloom ) { if ( settings::pipelines::bloom ) {
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom/comp.spv"); uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom/up.comp.spv");
blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom"); blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom-up");
auto& shader = blitter.material.getShader("compute", "bloom-up");
auto& shader = blitter.material.getShader("compute", "bloom");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL); shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("bright", this, VK_IMAGE_LAYOUT_GENERAL); shader.aliasAttachment("bright", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL); }
if ( settings::pipelines::bloom ) {
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom/down.comp.spv");
blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom-down");
auto& shader = blitter.material.getShader("compute", "bloom-down");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("bright", this, VK_IMAGE_LAYOUT_GENERAL);
shader.setSpecializationConstants({
{ "MIPS", mips },
});
shader.setDescriptorCounts({
{ "outImage", mips },
});
// atomic counter buffer
::atomicCounterBloom.initialize( (const void*) nullptr, sizeof(::AtomicCounter) * 1, uf::renderer::enums::Buffer::STORAGE );
shader.aliasBuffer("atomicCounterBloom", ::atomicCounterBloom);
for ( auto& view : ::bloomViews ) ::destroyImageView( this, view );
::bloomViews.clear();
::bloomViews.resize(mips);
shader.textures.clear();
ext::vulkan::Texture2D source; source.aliasAttachment( this->getAttachment("bright") );
for ( auto i = 0; i < mips; ++i ) {
auto& view = ::bloomViews[i];
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.pNext = NULL;
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
viewCreateInfo.subresourceRange.baseMipLevel = i;
viewCreateInfo.subresourceRange.layerCount = 1;
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCreateInfo.viewType = source.viewType;
viewCreateInfo.format = source.format;
viewCreateInfo.image = source.image;
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
VK_REGISTER_HANDLE(view);
{
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
}
}
} }
if ( settings::pipelines::culling ) { if ( settings::pipelines::culling ) {
@ -354,28 +403,32 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid"); auto& shader = blitter.material.getShader("compute", "depth-pyramid");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } ); auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
// depth pyramid
shader.aliasAttachment("depth", this);
shader.setSpecializationConstants({ shader.setSpecializationConstants({
{ "MIPS", mips }, { "MIPS", mips },
}); });
shader.setDescriptorCounts({ shader.setDescriptorCounts({
{ "inImage", mips },
{ "outImage", mips }, { "outImage", mips },
}); });
shader.aliasAttachment("depth", this); // atomic counter buffer
::atomicCounterDepth.initialize( (const void*) nullptr, sizeof(::AtomicCounter) * 1, uf::renderer::enums::Buffer::STORAGE );
shader.aliasBuffer("atomicCounterDepth", ::atomicCounterDepth);
ext::vulkan::Texture2D source; source.aliasAttachment( this->getAttachment("depthPyramid") ); for ( auto& view : ::depthPyramidViews ) ::destroyImageView( this, view );
source.sampler.descriptor.reduction.enabled = true;
source.sampler.descriptor.reduction.mode = VK_SAMPLER_REDUCTION_MODE_MIN;
for ( auto& view : ::depthPyramidViews ) {
vkDestroyImageView(device.logicalDevice, view, nullptr);
VK_UNREGISTER_HANDLE(view);
}
::depthPyramidViews.clear(); ::depthPyramidViews.clear();
::depthPyramidViews.resize(mips); ::depthPyramidViews.resize(mips);
shader.textures.clear(); shader.textures.clear();
storage.buffers.depthPyramid.destroy(true);
storage.buffers.depthPyramid.fromBuffers( NULL, 0, VK_FORMAT_R32_SFLOAT, width, height, 1, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
ext::vulkan::Texture2D& source = storage.buffers.depthPyramid;
source.sampler.descriptor.reduction.enabled = true;
source.sampler.descriptor.reduction.mode = VK_SAMPLER_REDUCTION_MODE_MIN;
for ( auto i = 0; i < mips; ++i ) { for ( auto i = 0; i < mips; ++i ) {
auto& view = ::depthPyramidViews[i]; auto& view = ::depthPyramidViews[i];
VkImageViewCreateInfo viewCreateInfo = {}; VkImageViewCreateInfo viewCreateInfo = {};
@ -392,22 +445,14 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view)); VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
VK_REGISTER_HANDLE(view); VK_REGISTER_HANDLE(view);
}
for ( auto i = 0; i < mips; ++i ) { {
auto& texture = shader.textures.emplace_back(); auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source ); texture.aliasTexture( source );
texture.view = ::depthPyramidViews[i]; texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL; texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors(); texture.updateDescriptors();
} }
for ( auto i = 0; i < mips; ++i ) {
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = ::depthPyramidViews[i];
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
} }
} }
@ -437,7 +482,18 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
} }
if ( settings::pipelines::bloom ) { if ( settings::pipelines::bloom ) {
descriptor.pipeline = "bloom"; descriptor.aux = uf::vector::mips( pod::Vector2ui{ width, height } );
descriptor.pipeline = "bloom-down";
descriptor.subpass = 0;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( !blitter.hasPipeline( descriptor ) ) {
blitter.initializePipeline( descriptor );
}
}
if ( settings::pipelines::bloom ) {
descriptor.aux = {};
descriptor.pipeline = "bloom-up";
descriptor.subpass = 0; descriptor.subpass = 0;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE; descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( !blitter.hasPipeline( descriptor ) ) { if ( !blitter.hasPipeline( descriptor ) ) {
@ -474,6 +530,49 @@ void ext::vulkan::DeferredRenderMode::tick() {
rebuild = true; rebuild = true;
renderTarget.initialize( *renderTarget.device ); renderTarget.initialize( *renderTarget.device );
if ( settings::pipelines::bloom ) {
auto& shader = blitter.material.getShader("compute", "bloom-down");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
shader.setSpecializationConstants({
{ "MIPS", mips },
});
shader.setDescriptorCounts({
{ "outImage", mips },
});
for ( auto& view : ::bloomViews ) ::destroyImageView( this, view );
::bloomViews.clear();
::bloomViews.resize(mips);
shader.textures.clear();
ext::vulkan::Texture2D source; source.aliasAttachment( this->getAttachment("bright") );
for ( auto i = 0; i < mips; ++i ) {
auto& view = ::bloomViews[i];
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.pNext = NULL;
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
viewCreateInfo.subresourceRange.baseMipLevel = i;
viewCreateInfo.subresourceRange.layerCount = 1;
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCreateInfo.viewType = source.viewType;
viewCreateInfo.format = source.format;
viewCreateInfo.image = source.image;
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
VK_REGISTER_HANDLE(view);
{
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
}
}
}
if ( settings::pipelines::culling ) { if ( settings::pipelines::culling ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid"); auto& shader = blitter.material.getShader("compute", "depth-pyramid");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } ); auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
@ -481,20 +580,17 @@ void ext::vulkan::DeferredRenderMode::tick() {
{ "MIPS", mips }, { "MIPS", mips },
}); });
shader.setDescriptorCounts({ shader.setDescriptorCounts({
{ "inImage", mips },
{ "outImage", mips }, { "outImage", mips },
}); });
shader.aliasAttachment("depth", this); storage.buffers.depthPyramid.destroy(true);
storage.buffers.depthPyramid.fromBuffers( NULL, 0, VK_FORMAT_R32_SFLOAT, width, height, 1, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
ext::vulkan::Texture2D source; source.aliasAttachment( this->getAttachment("depthPyramid") ); ext::vulkan::Texture2D& source = storage.buffers.depthPyramid;
source.sampler.descriptor.reduction.enabled = true; source.sampler.descriptor.reduction.enabled = true;
source.sampler.descriptor.reduction.mode = VK_SAMPLER_REDUCTION_MODE_MIN; source.sampler.descriptor.reduction.mode = VK_SAMPLER_REDUCTION_MODE_MIN;
for ( auto& view : ::depthPyramidViews ) { for ( auto& view : ::depthPyramidViews ) ::destroyImageView( this, view );
vkDestroyImageView(device->logicalDevice, view, nullptr);
VK_UNREGISTER_HANDLE(view);
}
::depthPyramidViews.clear(); ::depthPyramidViews.clear();
::depthPyramidViews.resize(mips); ::depthPyramidViews.resize(mips);
shader.textures.clear(); shader.textures.clear();
@ -516,22 +612,13 @@ void ext::vulkan::DeferredRenderMode::tick() {
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view)); VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
VK_REGISTER_HANDLE(view); VK_REGISTER_HANDLE(view);
} {
auto& texture = shader.textures.emplace_back();
for ( auto i = 0; i < mips; ++i ) { texture.aliasTexture( source );
auto& texture = shader.textures.emplace_back(); texture.view = view;
texture.aliasTexture( source ); texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.view = ::depthPyramidViews[i]; texture.updateDescriptors();
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL; }
texture.updateDescriptors();
}
for ( auto i = 0; i < mips; ++i ) {
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = ::depthPyramidViews[i];
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
} }
} }
} }
@ -582,7 +669,20 @@ void ext::vulkan::DeferredRenderMode::tick() {
} }
if ( settings::pipelines::bloom ) { if ( settings::pipelines::bloom ) {
descriptor.pipeline = "bloom"; descriptor.aux = uf::vector::mips( pod::Vector2ui{ width, height } );
descriptor.pipeline = "bloom-down";
descriptor.subpass = 0;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( blitter.hasPipeline( descriptor ) ) {
blitter.getPipeline( descriptor ).update( blitter, descriptor );
} else {
blitter.initializePipeline( descriptor );
}
}
if ( settings::pipelines::bloom ) {
descriptor.aux = {};
descriptor.pipeline = "bloom-up";
descriptor.subpass = 0; descriptor.subpass = 0;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE; descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( blitter.hasPipeline( descriptor ) ) { if ( blitter.hasPipeline( descriptor ) ) {
@ -659,6 +759,21 @@ void ext::vulkan::DeferredRenderMode::render() {
//unlockMutex( this->mostRecentCommandPoolId ); //unlockMutex( this->mostRecentCommandPoolId );
} }
void ext::vulkan::DeferredRenderMode::destroy() { void ext::vulkan::DeferredRenderMode::destroy() {
// cleanup
::atomicCounterDepth.destroy(false);
::atomicCounterBloom.destroy(false);
for ( auto& view : ::bloomViews ) {
vkDestroyImageView(device->logicalDevice, view, nullptr);
VK_UNREGISTER_HANDLE(view);
}
::bloomViews.clear();
for ( auto& view : ::depthPyramidViews ) {
vkDestroyImageView(device->logicalDevice, view, nullptr);
VK_UNREGISTER_HANDLE(view);
}
::depthPyramidViews.clear();
ext::vulkan::RenderMode::destroy(); ext::vulkan::RenderMode::destroy();
} }
@ -744,18 +859,6 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
size_t currentSubpass = 0; size_t currentSubpass = 0;
/*
// transition layers for read
for ( auto layer : layers ) {
layer->pipelineBarrier( commandBuffer, 0 );
}
*/
// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
// VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL
// VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
#if 1 #if 1
for ( auto& attachment : renderTarget.attachments ) { for ( auto& attachment : renderTarget.attachments ) {
// transition attachments to general attachments for imageStore // transition attachments to general attachments for imageStore
@ -863,11 +966,61 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
::transitionAttachmentsFrom( this, shader, commandBuffer ); ::transitionAttachmentsFrom( this, shader, commandBuffer );
} }
if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom") ) { if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom-down") ) {
auto& shader = blitter.material.getShader("compute", "bloom"); auto& shader = blitter.material.getShader("compute", "bloom-down");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
uint32_t dispatchX = (width + 63) / 64;
uint32_t dispatchY = (height + 63) / 64;
uint32_t numWorkGroups = dispatchX * dispatchY;
auto& pushConstant = shader.pushConstants.front().get<::PushConstants>();
pushConstant = {
.mips = mips,
.numWorkGroups = numWorkGroups,
.workGroupOffset = 0,
};
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = ""; descriptor.renderMode = "";
descriptor.pipeline = "bloom"; descriptor.aux = mips;
descriptor.pipeline = "bloom-down";
descriptor.bind.width = dispatchX * 256;
descriptor.bind.height = dispatchY;
descriptor.bind.depth = metadata.eyes;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
descriptor.subpass = 0;
// reset counter buffer
vkCmdFillBuffer(commandBuffer, ::atomicCounterBloom.buffer, 0, 4, 0);
VkMemoryBarrier counterBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
counterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
counterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &counterBarrier, 0, nullptr, 0, nullptr);
// transition attachments to general attachments for imageStore
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
::transitionAttachmentsTo( this, shader, commandBuffer );
// dispatch compute shader
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[down]" );
blitter.record( commandBuffer, descriptor );
/*
ext::vulkan::Texture2D source;
source.aliasAttachment( this->getAttachment("bright") );
source.generateMipmaps( commandBuffer );
*/
// transition attachments back to shader read layouts
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
::transitionAttachmentsFrom( this, shader, commandBuffer );
}
if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom-up") ) {
auto& shader = blitter.material.getShader("compute", "bloom-up");
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = "";
descriptor.pipeline = "bloom-up";
descriptor.bind.width = width; descriptor.bind.width = width;
descriptor.bind.height = height; descriptor.bind.height = height;
descriptor.bind.depth = metadata.eyes; descriptor.bind.depth = metadata.eyes;
@ -879,20 +1032,8 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
::transitionAttachmentsTo( this, shader, commandBuffer ); ::transitionAttachmentsTo( this, shader, commandBuffer );
// dispatch compute shader // dispatch compute shader
auto& attachmentColor = this->getAttachment("color"); // color device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[up]" );
auto& attachmentBright = this->getAttachment("bright"); // bloom blitter.record( commandBuffer, descriptor );
auto& attachmentScratch = this->getAttachment("scratch"); // pingpong
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[1]" );
blitter.record( commandBuffer, descriptor, 0, 1 );
cmdImageBarrier( commandBuffer, attachmentScratch.image, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL );
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[2]" );
blitter.record( commandBuffer, descriptor, 0, 2 );
cmdImageBarrier( commandBuffer, attachmentBright.image, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL );
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[3]" );
blitter.record( commandBuffer, descriptor, 0, 3 );
// transition attachments back to shader read layouts // transition attachments back to shader read layouts
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" ); device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
@ -900,80 +1041,51 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
} }
// construct depth-pyramid // construct depth-pyramid
#if 1
if ( settings::pipelines::culling && blitter.material.hasShader("compute", "depth-pyramid") ) { if ( settings::pipelines::culling && blitter.material.hasShader("compute", "depth-pyramid") ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid"); auto& shader = blitter.material.getShader("compute", "depth-pyramid");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } ); auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
uint32_t dispatchX = (width + 63) / 64;
uint32_t dispatchY = (height + 63) / 64;
uint32_t numWorkGroups = dispatchX * dispatchY;
auto& pushConstant = shader.pushConstants.front().get<::PushConstants>();
pushConstant = {
.mips = mips,
.numWorkGroups = numWorkGroups,
.workGroupOffset = 0,
};
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = ""; descriptor.renderMode = "";
descriptor.aux = mips; descriptor.aux = mips;
descriptor.pipeline = "depth-pyramid"; descriptor.pipeline = "depth-pyramid";
descriptor.bind.width = dispatchX * 256;
descriptor.bind.height = dispatchY;
descriptor.bind.depth = metadata.eyes; descriptor.bind.depth = metadata.eyes;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE; descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
descriptor.subpass = 0; descriptor.subpass = 0;
// dispatch compute shader // reset counter buffer
VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER}; vkCmdFillBuffer(commandBuffer, ::atomicCounterDepth.buffer, 0, 4, 0);
memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; VkMemoryBarrier counterBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; counterBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
counterBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT;
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 1, &counterBarrier, 0, nullptr, 0, nullptr);
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" ); device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
::transitionAttachmentsTo( this, shader, commandBuffer ); ::transitionAttachmentsTo( this, shader, commandBuffer );
for ( auto i = 0; i < mips; ++i ) { blitter.record(commandBuffer, descriptor);
// for some reason it dispatches at half the width without offsetting back...
descriptor.bind.width = std::max(1u, width >> (i - 1));
descriptor.bind.height = std::max(1u, height >> (i - 1));
blitter.record(commandBuffer, descriptor, 0, i);
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
}
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" ); device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
::transitionAttachmentsFrom( this, shader, commandBuffer ); ::transitionAttachmentsFrom( this, shader, commandBuffer );
} }
#endif
// post-renderpass commands // post-renderpass commands
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, { VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" ); device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
} ); } );
#if 0
if ( this->hasAttachment("depth") ) {
auto& attachment = this->getAttachment("depth");
ext::vulkan::Texture texture; texture.aliasAttachment( attachment );
texture.width = width;
texture.height = height;
texture.depth = 1;
texture.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
texture.descriptor.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL;
#if 1
imageMemoryBarrier.subresourceRange.layerCount = metadata.eyes;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageMemoryBarrier.subresourceRange );
#endif
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
texture.generateMipmaps(commandBuffer, eye);
}
#if 1
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, imageMemoryBarrier.subresourceRange );
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.layerCount = 1;
#endif
}
#endif #endif
#endif
/*
for ( auto layer : layers ) {
layer->pipelineBarrier( commandBuffer, 1 );
}
*/
} }
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" ); device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );

View File

@ -9,24 +9,41 @@ namespace {
subresourceRange.baseMipLevel = 0; subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1; subresourceRange.levelCount = 1;
subresourceRange.baseArrayLayer = 0; subresourceRange.baseArrayLayer = 0;
subresourceRange.layerCount = 1;
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.layerCount = self->metadata.eyes; subresourceRange.layerCount = self->metadata.eyes;
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
for ( auto& descriptor : shader.metadata.aliases.attachments ) { for ( auto& descriptor : shader.metadata.aliases.attachments ) {
if ( descriptor.layout == VK_IMAGE_LAYOUT_UNDEFINED ) continue; if ( descriptor.layout == VK_IMAGE_LAYOUT_UNDEFINED ) continue;
VkImage image = VK_NULL_HANDLE; VkImage image = VK_NULL_HANDLE;
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
size_t mips = 1;
if ( descriptor.renderMode ) { if ( descriptor.renderMode ) {
if ( descriptor.renderMode->hasAttachment(descriptor.name) ) if ( descriptor.renderMode->hasAttachment(descriptor.name) ) {
image = descriptor.renderMode->getAttachment(descriptor.name).image; auto& attachment = descriptor.renderMode->getAttachment(descriptor.name);
image = attachment.image;
mips = attachment.descriptor.mips;
initialLayout = attachment.descriptor.layout;
}
} else if ( self->hasAttachment(descriptor.name) ) { } else if ( self->hasAttachment(descriptor.name) ) {
if ( self->hasAttachment(descriptor.name) ) if ( self->hasAttachment(descriptor.name) ) {
image = self->getAttachment(descriptor.name).image; auto& attachment = self->getAttachment(descriptor.name);
image = attachment.image;
mips = attachment.descriptor.mips;
initialLayout = attachment.descriptor.layout;
}
} }
if ( image == VK_NULL_HANDLE ) continue; if ( image == VK_NULL_HANDLE ) continue;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, image, layout, descriptor.layout, subresourceRange ); uf::renderer::Texture::setImageLayout( commandBuffer, image, layout, descriptor.layout, subresourceRange );
if ( mips > 1 ) {
subresourceRange.baseMipLevel = 1;
subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
uf::renderer::Texture::setImageLayout( commandBuffer, image, initialLayout, descriptor.layout, subresourceRange );
}
} }
} }
void transitionAttachmentsFrom( void transitionAttachmentsFrom(
@ -39,24 +56,41 @@ namespace {
subresourceRange.baseMipLevel = 0; subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1; subresourceRange.levelCount = 1;
subresourceRange.baseArrayLayer = 0; subresourceRange.baseArrayLayer = 0;
subresourceRange.layerCount = 1;
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.layerCount = self->metadata.eyes; subresourceRange.layerCount = self->metadata.eyes;
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
for ( auto& descriptor : shader.metadata.aliases.attachments ) { for ( auto& descriptor : shader.metadata.aliases.attachments ) {
if ( descriptor.layout == VK_IMAGE_LAYOUT_UNDEFINED ) continue; if ( descriptor.layout == VK_IMAGE_LAYOUT_UNDEFINED ) continue;
VkImage image = VK_NULL_HANDLE; VkImage image = VK_NULL_HANDLE;
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
size_t mips = 1;
if ( descriptor.renderMode ) { if ( descriptor.renderMode ) {
if ( descriptor.renderMode->hasAttachment(descriptor.name) ) if ( descriptor.renderMode->hasAttachment(descriptor.name) ) {
image = descriptor.renderMode->getAttachment(descriptor.name).image; auto& attachment = descriptor.renderMode->getAttachment(descriptor.name);
image = attachment.image;
mips = attachment.descriptor.mips;
initialLayout = attachment.descriptor.layout;
}
} else if ( self->hasAttachment(descriptor.name) ) { } else if ( self->hasAttachment(descriptor.name) ) {
if ( self->hasAttachment(descriptor.name) ) if ( self->hasAttachment(descriptor.name) ) {
image = self->getAttachment(descriptor.name).image; auto& attachment = self->getAttachment(descriptor.name);
image = attachment.image;
mips = attachment.descriptor.mips;
initialLayout = attachment.descriptor.layout;
}
} }
if ( image == VK_NULL_HANDLE ) continue; if ( image == VK_NULL_HANDLE ) continue;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, layout, subresourceRange ); uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, layout, subresourceRange );
if ( mips > 1 ) {
subresourceRange.baseMipLevel = 1;
subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS;
uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, initialLayout, subresourceRange );
}
} }
} }
} }

View File

@ -12,8 +12,8 @@
#include <fstream> #include <fstream>
#include <regex> #include <regex>
#define VK_DEBUG_VALIDATION_MESSAGE(x)\ #define VK_DEBUG_VALIDATION_MESSAGE(...)\
// VK_VALIDATION_MESSAGE(x); //VK_VALIDATION_MESSAGE(__VA_ARGS__);
#define UF_SHADER_PARSE_AS_JSON 0 #define UF_SHADER_PARSE_AS_JSON 0
#if UF_SHADER_PARSE_AS_JSON #if UF_SHADER_PARSE_AS_JSON
@ -94,7 +94,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
#if UF_SHADER_TRACK_NAMES #if UF_SHADER_TRACK_NAMES
uf::stl::string path = uf::string::join(variableName, "."); uf::stl::string path = uf::string::join(variableName, ".");
path = uf::string::replace( path, ".[", "[" ); path = uf::string::replace( path, ".[", "[" );
VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump()); //VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = " << value.dump());
#endif #endif
// is strictly an int // is strictly an int
if ( value.is<int>(true) ) { if ( value.is<int>(true) ) {
@ -120,7 +120,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
#endif #endif
}; };
#if UF_SHADER_TRACK_NAMES #if UF_SHADER_TRACK_NAMES
VK_VALIDATION_MESSAGE("Updating {} in {}", name, filename); //VK_VALIDATION_MESSAGE("Updating {} in {}", name, filename);
// VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); // VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif #endif
parse(payload); parse(payload);
@ -264,7 +264,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
#if UF_SHADER_TRACK_NAMES #if UF_SHADER_TRACK_NAMES
uf::stl::string path = uf::string::join(variableName, "."); uf::stl::string path = uf::string::join(variableName, ".");
path = uf::string::replace( path, ".[", "[" ); path = uf::string::replace( path, ".[", "[" );
VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump()); //VK_VALIDATION_MESSAGE("[" << (byteBuffer - byteBufferStart) << " / "<< (byteBufferEnd - byteBuffer) <<"]\tInserting: " << path << " = (" << primitive << ") " << input.dump());
#endif #endif
pushValue( primitive, input ); pushValue( primitive, input );
} }
@ -275,12 +275,12 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
}; };
auto& definitions = metadata.json["definitions"]["uniforms"][name]; auto& definitions = metadata.json["definitions"]["uniforms"][name];
#if UF_SHADER_TRACK_NAMES #if UF_SHADER_TRACK_NAMES
VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename); //VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename);
VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); //VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif #endif
parseDefinition(payload, definitions); parseDefinition(payload, definitions);
#if UF_SHADER_TRACK_NAMES #if UF_SHADER_TRACK_NAMES
VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer)); //VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
#endif #endif
#endif #endif
return userdata; return userdata;
@ -489,14 +489,14 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
size_t bufferSize = comp.get_declared_struct_size(base_type); size_t bufferSize = comp.get_declared_struct_size(base_type);
if ( bufferSize <= 0 ) break; if ( bufferSize <= 0 ) break;
if ( bufferSize > device.properties.limits.maxUniformBufferRange ) { if ( bufferSize > device.properties.limits.maxUniformBufferRange ) {
VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer length of " << bufferSize << " for shader " << filename); VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer length of {} for shader {}", bufferSize, filename);
bufferSize = device.properties.limits.maxUniformBufferRange; bufferSize = device.properties.limits.maxUniformBufferRange;
} }
bufferSize = ALIGNED_SIZE( bufferSize, device.properties.limits.minUniformBufferOffsetAlignment ); bufferSize = ALIGNED_SIZE( bufferSize, device.properties.limits.minUniformBufferOffsetAlignment );
{ {
VK_DEBUG_VALIDATION_MESSAGE("Uniform size of " << bufferSize << " for shader " << filename); VK_DEBUG_VALIDATION_MESSAGE("Uniform size of {} for shader {}", bufferSize, filename);
// auto& uniform = uniforms.emplace_back(); // auto& uniform = uniforms.emplace_back();
// uniform.create( bufferSize ); // uniform.create( bufferSize );
} }
@ -564,7 +564,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
#define LOOP_RESOURCES( key, type ) for ( size_t i = 0; i < res.key.size(); ++i ) {\ #define LOOP_RESOURCES( key, type ) for ( size_t i = 0; i < res.key.size(); ++i ) {\
const auto& resource = res.key[i];\ const auto& resource = res.key[i];\
VK_DEBUG_VALIDATION_MESSAGE("["<<filename<<"] Found resource: "#type " with binding: " << comp.get_decoration(resource.id, spv::DecorationBinding));\ VK_DEBUG_VALIDATION_MESSAGE("[{}] Found resource: {} with binding: {}", filename, #type, comp.get_decoration(resource.id, spv::DecorationBinding));\
parseResource( resource, type, i );\ parseResource( resource, type, i );\
} }
LOOP_RESOURCES( sampled_images, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ); LOOP_RESOURCES( sampled_images, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER );
@ -667,16 +667,17 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
if ( size <= 0 ) continue; if ( size <= 0 ) continue;
// not a multiple of 4, for some reason // not a multiple of 4, for some reason
if ( size % 4 != 0 ) { if ( size % 4 != 0 ) {
VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename << ", must be multiple of 4, correcting..."); VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of {} for shader {}, must be multiple of 4, correcting...", size, filename);
size /= 4; size /= 4;
++size; ++size;
size *= 4; size *= 4;
} }
if ( size > device.properties.limits.maxPushConstantsSize ) { if ( size > device.properties.limits.maxPushConstantsSize ) {
VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename); VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of {} for shader {}", size, filename);
//VK_DEBUG_VALIDATION_MESSAGE("Invalid push constant length of " << size << " for shader " << filename);
size = device.properties.limits.maxPushConstantsSize; size = device.properties.limits.maxPushConstantsSize;
} }
VK_DEBUG_VALIDATION_MESSAGE("Push constant size of " << size << " for shader " << filename); VK_DEBUG_VALIDATION_MESSAGE("Push constant size of {} for shader {},", size, filename);
{ {
auto& pushConstant = pushConstants.emplace_back(); auto& pushConstant = pushConstants.emplace_back();
pushConstant.create( size ); pushConstant.create( size );
@ -724,7 +725,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
specializationMapEntries.emplace_back(specializationMapEntry); specializationMapEntries.emplace_back(specializationMapEntry);
} }
specializationConstants.create( specializationSize ); specializationConstants.create( specializationSize );
VK_DEBUG_VALIDATION_MESSAGE("Specialization constants size of " << specializationSize << " for shader " << filename); VK_DEBUG_VALIDATION_MESSAGE("Specialization constants size of {} for shader {}", specializationSize, filename);
uint8_t* s = (uint8_t*) (void*) specializationConstants; uint8_t* s = (uint8_t*) (void*) specializationConstants;
size_t offset = 0; size_t offset = 0;
@ -798,7 +799,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
definition.validate = false; definition.validate = false;
} break; } break;
default: { default: {
VK_DEBUG_VALIDATION_MESSAGE("Unregistered specialization constant type at offset " << offset << " for shader " << filename ); VK_DEBUG_VALIDATION_MESSAGE("Unregistered specialization constant type at offset {} for shader {}", offset, filename );
} break; } break;
} }
#if UF_SHADER_PARSE_AS_JSON #if UF_SHADER_PARSE_AS_JSON
@ -806,7 +807,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
member["size"] = size; member["size"] = size;
member["default"] = member["value"]; member["default"] = member["value"];
metadata.json["specializationConstants"].emplace_back(member); metadata.json["specializationConstants"].emplace_back(member);
VK_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as<uf::stl::string>() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename ); //VK_DEBUG_VALIDATION_MESSAGE("Specialization constant: " << member["type"].as<uf::stl::string>() << " " << name << " = " << member["value"].dump() << "; at offset " << offset << " for shader " << filename );
#endif #endif
memcpy( &s[offset], &buffer, size ); memcpy( &s[offset], &buffer, size );
@ -859,7 +860,7 @@ bool ext::vulkan::Shader::validate() {
if ( it == uniforms.end() ) break; if ( it == uniforms.end() ) break;
auto& uniform = *(it++); auto& uniform = *(it++);
if ( uniform.data().len != buffer.allocationInfo.size ) { if ( uniform.data().len != buffer.allocationInfo.size ) {
VK_DEBUG_VALIDATION_MESSAGE("Uniform size mismatch: Expected " << buffer.allocationInfo.size << ", got " << uniform.data().len << "; fixing..."); VK_DEBUG_VALIDATION_MESSAGE("Uniform size mismatch: Expected {}, got {}; fixing...", buffer.allocationInfo.size, uniform.data().len);
uniform.destroy(); uniform.destroy();
uniform.create(buffer.allocationInfo.size); uniform.create(buffer.allocationInfo.size);
valid = false; valid = false;

View File

@ -205,12 +205,15 @@ void ext::vulkan::Texture::destroy( bool defer ) {
if ( !device || !device->logicalDevice || aliased ) return; // device->logicalDevice should never be null, but it happens, somehow if ( !device || !device->logicalDevice || aliased ) return; // device->logicalDevice should never be null, but it happens, somehow
if ( defer ) { if ( defer ) {
ext::vulkan::gc::textures.emplace_back( *this ); ext::vulkan::mutex.lock();
device->transient.textures.emplace_back(*this);
ext::vulkan::mutex.unlock();
return; return;
} }
if ( view != VK_NULL_HANDLE ) { if ( view != VK_NULL_HANDLE ) {
vkDestroyImageView(device->logicalDevice, view, nullptr); vkDestroyImageView(device->logicalDevice, view, nullptr);
VK_UNREGISTER_HANDLE( view );
view = VK_NULL_HANDLE; view = VK_NULL_HANDLE;
} }
if ( image != VK_NULL_HANDLE ) { if ( image != VK_NULL_HANDLE ) {
@ -581,6 +584,7 @@ void ext::vulkan::Texture::fromBuffers(
viewCreateInfo.subresourceRange.levelCount = this->mips; viewCreateInfo.subresourceRange.levelCount = this->mips;
viewCreateInfo.image = image; viewCreateInfo.image = image;
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view)); VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
VK_REGISTER_HANDLE( view );
{ {
auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS); auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS);
@ -890,7 +894,7 @@ void ext::vulkan::Texture::generateMipmaps( VkCommandBuffer commandBuffer, uint3
int32_t mipWidth = width; int32_t mipWidth = width;
int32_t mipHeight = height; int32_t mipHeight = height;
int32_t mipDepth = depth; int32_t mipDepth = MAX(1, depth);
for ( size_t i = 1; i < this->mips; ++i ) { for ( size_t i = 1; i < this->mips; ++i ) {
// transition previous layer to read from it // transition previous layer to read from it
barrier.subresourceRange.baseMipLevel = i - 1; barrier.subresourceRange.baseMipLevel = i - 1;
@ -1150,7 +1154,7 @@ uf::Image ext::vulkan::Texture3D::screenshot( uint32_t layerID ) {
imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopy.dstSubresource.baseArrayLayer = 0; imageCopy.dstSubresource.baseArrayLayer = 0;
imageCopy.dstSubresource.layerCount = 1; imageCopy.dstSubresource.layerCount = 1;
imageCopy.dstOffset = { 0, 0, 0 }; imageCopy.dstOffset = { 0, 0, layerID };
imageCopy.extent = { this->width, this->height, 1 }; imageCopy.extent = { this->width, this->height, 1 };
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "copyImage" ); device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "copyImage" );

View File

@ -116,8 +116,6 @@ uint32_t ext::vulkan::states::frameAccumulate = 0;
bool ext::vulkan::states::frameAccumulateReset = false; bool ext::vulkan::states::frameAccumulateReset = false;
uint32_t ext::vulkan::states::frameSkip = 0; uint32_t ext::vulkan::states::frameSkip = 0;
uf::stl::vector<ext::vulkan::Texture> ext::vulkan::gc::textures;
uf::ThreadUnique<ext::vulkan::RenderMode*> ext::vulkan::currentRenderMode; uf::ThreadUnique<ext::vulkan::RenderMode*> ext::vulkan::currentRenderMode;
ext::vulkan::Buffer ext::vulkan::scratchBuffer; ext::vulkan::Buffer ext::vulkan::scratchBuffer;
@ -495,6 +493,7 @@ void ext::vulkan::initialize( bool soft ) {
void ext::vulkan::tick() { void ext::vulkan::tick() {
// ext::vulkan::mutex.lock(); // ext::vulkan::mutex.lock();
if ( ext::vulkan::states::resized || ext::vulkan::settings::experimental::rebuildOnTickBegin ) { if ( ext::vulkan::states::resized || ext::vulkan::settings::experimental::rebuildOnTickBegin ) {
synchronize(0b11);
ext::vulkan::states::rebuild = true; ext::vulkan::states::rebuild = true;
::skip = true; ::skip = true;
} }
@ -534,13 +533,6 @@ void ext::vulkan::tick() {
uf::thread::execute( tasks ); uf::thread::execute( tasks );
/*
for ( auto& texture : ext::vulkan::gc::textures ) {
texture.destroy( false );
}
ext::vulkan::gc::textures.clear();
*/
if ( ext::vulkan::states::rebuild && ext::vulkan::settings::experimental::skipRenderOnRebuild ) ::skip = true; if ( ext::vulkan::states::rebuild && ext::vulkan::settings::experimental::skipRenderOnRebuild ) ::skip = true;
ext::vulkan::states::rebuild = false; ext::vulkan::states::rebuild = false;
@ -666,6 +658,9 @@ void ext::vulkan::render() {
for ( auto& buffer : transient.buffers ) buffer.destroy(false); for ( auto& buffer : transient.buffers ) buffer.destroy(false);
transient.buffers.clear(); transient.buffers.clear();
for ( auto& texture : transient.textures ) texture.destroy(false);
transient.textures.clear();
for ( auto& as : transient.ass ) { for ( auto& as : transient.ass ) {
uf::renderer::vkDestroyAccelerationStructureKHR(device, as.handle, nullptr); uf::renderer::vkDestroyAccelerationStructureKHR(device, as.handle, nullptr);
VK_UNREGISTER_HANDLE( as.handle ); VK_UNREGISTER_HANDLE( as.handle );
@ -677,7 +672,7 @@ void ext::vulkan::destroy( bool soft ) {
ext::vulkan::flushCommandBuffers(); ext::vulkan::flushCommandBuffers();
// ext::vulkan::mutex.lock(); // ext::vulkan::mutex.lock();
synchronize(); synchronize(0b11);
#if UF_USE_FFX_FSR #if UF_USE_FFX_FSR
if ( settings::pipelines::fsr ) { if ( settings::pipelines::fsr ) {
@ -725,7 +720,7 @@ void ext::vulkan::destroy( bool soft ) {
// ext::vulkan::mutex.unlock(); // ext::vulkan::mutex.unlock();
// check for any leaked resources // check for any leaked resources
if ( false ) { if ( ext::vulkan::settings::validation::checkpoints ) {
UF_MSG_DEBUG("Leaked resources:"); UF_MSG_DEBUG("Leaked resources:");
for ( auto& resource : ext::vulkan::Resource<VkBuffer_T*>::handles ) { for ( auto& resource : ext::vulkan::Resource<VkBuffer_T*>::handles ) {