neurotic optimizations (overhauled depth pyramid and bloom to ffx-sdp), more fixes
This commit is contained in:
parent
fd9036ee39
commit
6d05ab865a
@ -110,7 +110,7 @@
|
||||
"default stage buffers": true,
|
||||
"default defer buffer destroy": true,
|
||||
"default command buffer immediate": true,
|
||||
"multithreaded recording": true
|
||||
"multithreaded recording": false
|
||||
},
|
||||
"pipelines": {
|
||||
"deferred": true,
|
||||
@ -147,7 +147,8 @@
|
||||
"deviceCoherentMemory",
|
||||
"robustBufferAccess",
|
||||
"samplerAnisotropy",
|
||||
"sampleRateShading"
|
||||
"sampleRateShading",
|
||||
"samplerFilterMinmax"
|
||||
],
|
||||
"featureChain": []
|
||||
},
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
{
|
||||
// "import": "./rp_downtown_v2.json"
|
||||
"import": "./ss2_medsci1.json"
|
||||
// "import": "./ss2_medsci1.json"
|
||||
// "import": "./test_grid.json"
|
||||
// "import": "./sh2_mcdonalds.json"
|
||||
// "import": "./animal_crossing.json"
|
||||
// "import": "./mds_mcdonalds.json"
|
||||
"import": "./mds_mcdonalds.json"
|
||||
// "import": "./gm_construct.json"
|
||||
}
|
||||
@ -44,6 +44,7 @@ void gammaCorrect( inout vec3 color, float gamma ) {
|
||||
}
|
||||
void toneMap( inout vec4 color, float exposure ) { toneMap(color.rgb, exposure); }
|
||||
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 v0 = val0;
|
||||
@ -152,6 +153,7 @@ vec3 decodeSrgb(vec3 rgb) {
|
||||
const vec3 c = step(vec3(0.04045), rgb);
|
||||
return mix(a, b, c);
|
||||
}
|
||||
#if !SPD && (DEFERRED || FRAGMENT || COMPUTE || RT)
|
||||
bool validTextureIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex && textureIndex < MAX_TEXTURES;
|
||||
}
|
||||
@ -160,7 +162,6 @@ bool validCubemapIndex( int textureIndex ) {
|
||||
return 0 <= textureIndex && textureIndex < MAX_CUBEMAPS;
|
||||
}
|
||||
#endif
|
||||
#if !BLOOM && (DEFERRED || FRAGMENT || COMPUTE || RT)
|
||||
bool validTextureIndex( uint id ) {
|
||||
return 0 <= id && id < MAX_TEXTURES;
|
||||
}
|
||||
|
||||
@ -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) );
|
||||
}
|
||||
}
|
||||
131
bin/data/shaders/display/bloom/down.comp.glsl
Normal file
131
bin/data/shaders/display/bloom/down.comp.glsl
Normal 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)
|
||||
);
|
||||
}
|
||||
60
bin/data/shaders/display/bloom/up.comp.glsl
Normal file
60
bin/data/shaders/display/bloom/up.comp.glsl
Normal 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) );
|
||||
}
|
||||
@ -159,7 +159,7 @@ void postProcess() {
|
||||
#if FOG
|
||||
fog( surface.ray, surface.fragment.rgb, surface.fragment.a );
|
||||
#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;
|
||||
//if ( bloom ) toneMap( surface.fragment.rgb, brightness );
|
||||
vec4 outFragColor = vec4(surface.fragment.rgb, 1.0);
|
||||
@ -184,7 +184,7 @@ void postProcess() {
|
||||
}
|
||||
|
||||
IMAGE_STORE( imageColor, outFragColor );
|
||||
IMAGE_STORE( imageBright, outFragBright );
|
||||
//IMAGE_STORE( imageBright, outFragBright );
|
||||
IMAGE_STORE( imageMotion, vec4(outFragMotion, 0, 0) );
|
||||
}
|
||||
|
||||
|
||||
@ -1,35 +1,96 @@
|
||||
#version 450
|
||||
#pragma shader_stage(compute)
|
||||
|
||||
//#extension GL_EXT_nonuniform_qualifier : enable
|
||||
|
||||
layout (constant_id = 0) const uint MIPS = 6;
|
||||
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
|
||||
#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( push_constant ) uniform PushBlock {
|
||||
uint _;
|
||||
uint pass;
|
||||
} PushConstant;
|
||||
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) uniform sampler2D samplerDepth;
|
||||
layout (binding = 1) uniform sampler2D inImage[MIPS];
|
||||
layout (binding = 2, r32f) uniform writeonly image2D outImage[MIPS];
|
||||
layout (binding = 1, r32f) coherent uniform 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() {
|
||||
int mip = int(PushConstant.pass);
|
||||
|
||||
float depth;
|
||||
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
|
||||
if ( mip == 0 ) {
|
||||
depth = texelFetch(samplerDepth, pos, 0).r;
|
||||
} else {
|
||||
depth = texture(inImage[mip - 1], (vec2(gl_GlobalInvocationID.xy) + vec2(0.5)) / imageSize( outImage[mip] )).x;
|
||||
}
|
||||
|
||||
imageStore(outImage[mip], pos, vec4(depth));
|
||||
SpdDownsample(
|
||||
AU2(gl_WorkGroupID.xy),
|
||||
AU1(gl_LocalInvocationIndex),
|
||||
AU1(PushConstant_.mips - 1),
|
||||
AU1(PushConstant_.numWorkGroups),
|
||||
AU1(PushConstant_.workGroupOffset)
|
||||
);
|
||||
}
|
||||
1907
bin/data/shaders/ext/ffx_a.h
Normal file
1907
bin/data/shaders/ext/ffx_a.h
Normal file
File diff suppressed because it is too large
Load Diff
1297
bin/data/shaders/ext/ffx_spd.h
Normal file
1297
bin/data/shaders/ext/ffx_spd.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
||||
#extension GL_EXT_samplerless_texture_functions : enable
|
||||
|
||||
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 QUERY_MIPMAPS 1
|
||||
@ -73,106 +73,100 @@ layout (std140, binding = 3) buffer Objects {
|
||||
|
||||
layout (binding = 4) uniform sampler2D samplerDepth;
|
||||
|
||||
shared vec4 sharedPlanes[PASSES][6];
|
||||
|
||||
vec4 normalizePlane( vec4 p ) {
|
||||
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;
|
||||
return p / length(p.xyz);
|
||||
}
|
||||
|
||||
void main() {
|
||||
const uint gID = gl_GlobalInvocationID.x;
|
||||
if ( !(0 <= gID && gID < drawCommands.length()) ) return;
|
||||
const uint gID = gl_GlobalInvocationID.x;
|
||||
const uint lID = gl_LocalInvocationIndex;
|
||||
|
||||
bool visible = frustumCull( gID );
|
||||
if ( visible ) visible = occlusionCull( gID );
|
||||
drawCommands[gID].instances = visible ? 1 : 0;
|
||||
if ( lID == 0 ) {
|
||||
for (uint pass = 0; pass < PushConstant.passes; ++pass) {
|
||||
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;
|
||||
}
|
||||
@ -390,7 +390,7 @@ void main() {
|
||||
#endif
|
||||
{
|
||||
#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);
|
||||
// imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), outFragBright);
|
||||
#endif
|
||||
|
||||
@ -111,6 +111,8 @@ namespace pod {
|
||||
uf::renderer::Buffer material;
|
||||
uf::renderer::Buffer texture;
|
||||
uf::renderer::Buffer light;
|
||||
|
||||
uf::renderer::Texture2D depthPyramid;
|
||||
} buffers;
|
||||
}/* storage*/;
|
||||
};
|
||||
|
||||
@ -28,6 +28,8 @@ namespace ext {
|
||||
operator VkCommandBuffer() { return handle; }
|
||||
};
|
||||
|
||||
struct Texture;
|
||||
|
||||
struct UF_API Device {
|
||||
VkInstance instance;
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
@ -86,6 +88,7 @@ namespace ext {
|
||||
|
||||
uf::stl::vector<Buffer> buffers;
|
||||
uf::stl::vector<AccelerationStructure> ass;
|
||||
uf::stl::vector<Texture> textures;
|
||||
} transient;
|
||||
|
||||
struct {
|
||||
|
||||
@ -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 destroy();
|
||||
|
||||
uf::stl::vector<Shader*> getShaders( uf::stl::vector<Shader>& );
|
||||
uf::stl::vector<const Shader*> getShaders( const uf::stl::vector<Shader>& ) const;
|
||||
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::string& = "" ) const;
|
||||
|
||||
void collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const;
|
||||
};
|
||||
|
||||
@ -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( 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 );
|
||||
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); }
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
#define VK_DEFAULT_STAGE_BUFFERS ext::vulkan::settings::defaultStageBuffers
|
||||
#define VK_DEFAULT_DEFER_BUFFER_DESTROY ext::vulkan::settings::defaultDeferBufferDestroy
|
||||
#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 vulkan {
|
||||
|
||||
@ -182,10 +182,6 @@ namespace ext {
|
||||
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 Allocator allocator;
|
||||
|
||||
@ -938,8 +938,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
|
||||
#if UF_USE_VULKAN
|
||||
// only update this when requested
|
||||
// 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") ) {
|
||||
auto& shader = graphic.material.getShader("compute", "bloom");
|
||||
if ( uf::renderer::settings::pipelines::bloom && metadata.bloom.outOfDate && graphic.material.hasShader("compute", "bloom-down") ) {
|
||||
auto& shaderDown = graphic.material.getShader("compute", "bloom-down");
|
||||
auto& shaderUp = graphic.material.getShader("compute", "bloom-up");
|
||||
|
||||
struct UniformDescriptor {
|
||||
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;
|
||||
|
||||
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 {
|
||||
|
||||
@ -196,7 +196,6 @@ namespace {
|
||||
|
||||
// compute shader
|
||||
auto& shader = graphic.material.getShader("compute", uf::renderer::settings::pipelines::names::culling);
|
||||
shader.aliasAttachment("depthPyramid");
|
||||
}
|
||||
// vxgi pipeline
|
||||
if ( uf::renderer::settings::pipelines::vxgi ) {
|
||||
@ -479,6 +478,9 @@ namespace {
|
||||
shader.aliasBuffer( "indirect", *indirect );
|
||||
shader.aliasBuffer( "instance", storage.buffers.instance );
|
||||
shader.aliasBuffer( "object", storage.buffers.object );
|
||||
|
||||
shader.textures.clear();
|
||||
shader.textures.emplace_back().aliasTexture( storage.buffers.depthPyramid );
|
||||
}
|
||||
|
||||
// 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 ) {
|
||||
soft = false;
|
||||
#if UF_USE_VULKAN
|
||||
/*
|
||||
for ( auto& texture : uf::renderer::gc::textures ) {
|
||||
texture.destroy( false );
|
||||
}
|
||||
uf::renderer::gc::textures.clear();
|
||||
*/
|
||||
#endif
|
||||
|
||||
// cleanup graphic handles
|
||||
|
||||
@ -41,7 +41,7 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
|
||||
this->metadata.type = descriptor.pipeline;
|
||||
Device& device = *graphic.device;
|
||||
|
||||
auto shaders = getShaders( graphic.material.shaders );
|
||||
auto shaders = getShaders( graphic.material.shaders, descriptor.pipeline );
|
||||
assert( shaders.size() > 0 );
|
||||
|
||||
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 );
|
||||
}
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
// automatically bind to our default push constants
|
||||
if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) {
|
||||
struct PushConstant {
|
||||
uint32_t pass;
|
||||
@ -450,7 +454,10 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
|
||||
}
|
||||
|
||||
// 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
|
||||
#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);
|
||||
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<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::vector<ext::vulkan::Shader*> res;
|
||||
bool isCompute = false;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
map[shader.metadata.type] = &shader;
|
||||
}
|
||||
for ( auto pair : map ) res.insert( res.begin(), pair.second);
|
||||
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::vector<const ext::vulkan::Shader*> res;
|
||||
bool isCompute = false;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
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 {
|
||||
if ( !process ) return;
|
||||
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;
|
||||
}
|
||||
|
||||
auto& pipeline = this->getPipeline( descriptor );
|
||||
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;
|
||||
}
|
||||
if ( !pipeline.metadata.process ) return;
|
||||
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 ) {
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) return;
|
||||
if (
|
||||
|
||||
@ -273,8 +273,8 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
// swapchain.destroy();
|
||||
swapchain.initialize( device );
|
||||
// bind swapchain images
|
||||
images.resize( ext::vulkan::swapchain.buffers );
|
||||
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device, swapchain.swapChain, &swapchain.buffers, images.data()));
|
||||
::images.resize( ext::vulkan::swapchain.buffers );
|
||||
VK_CHECK_RESULT(vkGetSwapchainImagesKHR( device, swapchain.swapChain, &swapchain.buffers, ::images.data()));
|
||||
// create image views for swapchain images
|
||||
|
||||
renderTarget.attachments.clear();
|
||||
@ -302,7 +302,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
colorAttachmentView.subresourceRange.layerCount = 1;
|
||||
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
colorAttachmentView.flags = 0;
|
||||
colorAttachmentView.image = images[frame];
|
||||
colorAttachmentView.image = ::images[frame];
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &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.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
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;
|
||||
|
||||
metadata.attachments["color["+std::to_string((int) frame)+"]"] = attachmentIndex++;
|
||||
@ -530,7 +530,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
// Create framebuffer
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
std::array<VkImageView, 2> attachments;
|
||||
@ -555,7 +555,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
#if 0
|
||||
if ( true ) {
|
||||
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 = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = 0;
|
||||
@ -652,10 +652,11 @@ void ext::vulkan::BaseRenderMode::destroy() {
|
||||
}
|
||||
|
||||
for ( auto& image : ::images ) {
|
||||
// vkDestroyImage( *device, image, nullptr );
|
||||
// vkDestroyImage( *device, image, nullptr ); // destroyed via vkDestroySwapchainKHR
|
||||
VK_UNREGISTER_HANDLE( image );
|
||||
image = VK_NULL_HANDLE;
|
||||
}
|
||||
::images.clear();
|
||||
|
||||
ext::vulkan::RenderMode::destroy();
|
||||
|
||||
|
||||
@ -26,22 +26,34 @@
|
||||
|
||||
namespace {
|
||||
const uf::stl::string DEFERRED_MODE = "compute";
|
||||
ext::vulkan::Texture depthPyramid;
|
||||
|
||||
uf::stl::vector<VkImageView> depthPyramidViews;
|
||||
|
||||
void cmdImageBarrier(VkCommandBuffer commandBuffer, VkImage image, VkAccessFlags srcAccess, VkAccessFlags dstAccess, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
|
||||
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);
|
||||
uf::stl::vector<VkImageView> bloomViews;
|
||||
|
||||
ext::vulkan::Buffer atomicCounterBloom;
|
||||
ext::vulkan::Buffer atomicCounterDepth;
|
||||
|
||||
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"
|
||||
@ -64,8 +76,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
|
||||
struct {
|
||||
size_t id, bary, depth, uv, normal;
|
||||
size_t color, bright, motion, scratch, output;
|
||||
size_t depthPyramid;
|
||||
size_t color, bright, motion, output;
|
||||
} attachments = {};
|
||||
|
||||
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{
|
||||
/*.format = */ext::vulkan::settings::formats::depth,
|
||||
/*.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,
|
||||
/*.samples = */msaa,
|
||||
//*.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,
|
||||
/*.blend =*/ blend,
|
||||
/*.samples =*/ 1,
|
||||
});
|
||||
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,
|
||||
/*.mips =*/ mips,
|
||||
});
|
||||
attachments.motion = renderTarget.attach(RenderTarget::Attachment::Descriptor{
|
||||
// /*.format = */VK_FORMAT_R32G32B32A32_SFLOAT,
|
||||
@ -143,14 +148,6 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
/*.blend = */false,
|
||||
/*.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;
|
||||
|
||||
@ -164,10 +161,8 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
#endif
|
||||
|
||||
metadata.attachments["depth"] = attachments.depth;
|
||||
metadata.attachments["depthPyramid"] = attachments.depthPyramid;
|
||||
metadata.attachments["color"] = attachments.color;
|
||||
metadata.attachments["bright"] = attachments.bright;
|
||||
metadata.attachments["scratch"] = attachments.scratch;
|
||||
metadata.attachments["motion"] = attachments.motion;
|
||||
|
||||
metadata.attachments["output"] = attachments.color;
|
||||
@ -339,13 +334,67 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
}
|
||||
|
||||
if ( settings::pipelines::bloom ) {
|
||||
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom/comp.spv");
|
||||
blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom");
|
||||
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-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("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 ) {
|
||||
@ -354,27 +403,31 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
|
||||
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
|
||||
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
|
||||
// depth pyramid
|
||||
shader.aliasAttachment("depth", this);
|
||||
|
||||
shader.setSpecializationConstants({
|
||||
{ "MIPS", mips },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "inImage", 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") );
|
||||
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);
|
||||
}
|
||||
for ( auto& view : ::depthPyramidViews ) ::destroyImageView( this, view );
|
||||
::depthPyramidViews.clear();
|
||||
::depthPyramidViews.resize(mips);
|
||||
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 ) {
|
||||
auto& view = ::depthPyramidViews[i];
|
||||
@ -392,22 +445,14 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_REGISTER_HANDLE(view);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
{
|
||||
auto& texture = shader.textures.emplace_back();
|
||||
texture.aliasTexture( source );
|
||||
texture.view = view;
|
||||
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
texture.updateDescriptors();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -437,7 +482,18 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
|
||||
}
|
||||
|
||||
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.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
|
||||
if ( !blitter.hasPipeline( descriptor ) ) {
|
||||
@ -474,6 +530,49 @@ void ext::vulkan::DeferredRenderMode::tick() {
|
||||
rebuild = true;
|
||||
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 ) {
|
||||
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
|
||||
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
|
||||
@ -481,20 +580,17 @@ void ext::vulkan::DeferredRenderMode::tick() {
|
||||
{ "MIPS", mips },
|
||||
});
|
||||
shader.setDescriptorCounts({
|
||||
{ "inImage", 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.mode = VK_SAMPLER_REDUCTION_MODE_MIN;
|
||||
|
||||
for ( auto& view : ::depthPyramidViews ) {
|
||||
vkDestroyImageView(device->logicalDevice, view, nullptr);
|
||||
VK_UNREGISTER_HANDLE(view);
|
||||
}
|
||||
for ( auto& view : ::depthPyramidViews ) ::destroyImageView( this, view );
|
||||
::depthPyramidViews.clear();
|
||||
::depthPyramidViews.resize(mips);
|
||||
shader.textures.clear();
|
||||
@ -515,23 +611,14 @@ void ext::vulkan::DeferredRenderMode::tick() {
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_REGISTER_HANDLE(view);
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
{
|
||||
auto& texture = shader.textures.emplace_back();
|
||||
texture.aliasTexture( source );
|
||||
texture.view = view;
|
||||
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
texture.updateDescriptors();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -582,7 +669,20 @@ void ext::vulkan::DeferredRenderMode::tick() {
|
||||
}
|
||||
|
||||
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.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
|
||||
if ( blitter.hasPipeline( descriptor ) ) {
|
||||
@ -659,6 +759,21 @@ void ext::vulkan::DeferredRenderMode::render() {
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
@ -744,18 +859,6 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
|
||||
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
|
||||
for ( auto& attachment : renderTarget.attachments ) {
|
||||
// transition attachments to general attachments for imageStore
|
||||
@ -863,11 +966,61 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
::transitionAttachmentsFrom( this, shader, commandBuffer );
|
||||
}
|
||||
|
||||
if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom") ) {
|
||||
auto& shader = blitter.material.getShader("compute", "bloom");
|
||||
if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom-down") ) {
|
||||
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;
|
||||
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.height = height;
|
||||
descriptor.bind.depth = metadata.eyes;
|
||||
@ -879,20 +1032,8 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
::transitionAttachmentsTo( this, shader, commandBuffer );
|
||||
|
||||
// dispatch compute shader
|
||||
auto& attachmentColor = this->getAttachment("color"); // color
|
||||
auto& attachmentBright = this->getAttachment("bright"); // bloom
|
||||
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 );
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[up]" );
|
||||
blitter.record( commandBuffer, descriptor );
|
||||
|
||||
// transition attachments back to shader read layouts
|
||||
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
|
||||
#if 1
|
||||
if ( settings::pipelines::culling && blitter.material.hasShader("compute", "depth-pyramid") ) {
|
||||
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
|
||||
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;
|
||||
descriptor.renderMode = "";
|
||||
descriptor.aux = mips;
|
||||
descriptor.pipeline = "depth-pyramid";
|
||||
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;
|
||||
|
||||
// dispatch compute shader
|
||||
VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
|
||||
memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
// reset counter buffer
|
||||
vkCmdFillBuffer(commandBuffer, ::atomicCounterDepth.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);
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
::transitionAttachmentsTo( this, shader, commandBuffer );
|
||||
|
||||
for ( auto i = 0; i < mips; ++i ) {
|
||||
// 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 );
|
||||
}
|
||||
blitter.record(commandBuffer, descriptor);
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
::transitionAttachmentsFrom( this, shader, commandBuffer );
|
||||
}
|
||||
#endif
|
||||
|
||||
// post-renderpass commands
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
|
||||
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
|
||||
|
||||
/*
|
||||
for ( auto layer : layers ) {
|
||||
layer->pipelineBarrier( commandBuffer, 1 );
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
|
||||
|
||||
@ -9,24 +9,41 @@ namespace {
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.layerCount = self->metadata.eyes;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
for ( auto& descriptor : shader.metadata.aliases.attachments ) {
|
||||
if ( descriptor.layout == VK_IMAGE_LAYOUT_UNDEFINED ) continue;
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
size_t mips = 1;
|
||||
|
||||
if ( descriptor.renderMode ) {
|
||||
if ( descriptor.renderMode->hasAttachment(descriptor.name) )
|
||||
image = descriptor.renderMode->getAttachment(descriptor.name).image;
|
||||
if ( descriptor.renderMode->hasAttachment(descriptor.name) ) {
|
||||
auto& attachment = descriptor.renderMode->getAttachment(descriptor.name);
|
||||
image = attachment.image;
|
||||
mips = attachment.descriptor.mips;
|
||||
initialLayout = attachment.descriptor.layout;
|
||||
}
|
||||
|
||||
} else if ( self->hasAttachment(descriptor.name) ) {
|
||||
if ( self->hasAttachment(descriptor.name) )
|
||||
image = self->getAttachment(descriptor.name).image;
|
||||
if ( self->hasAttachment(descriptor.name) ) {
|
||||
auto& attachment = self->getAttachment(descriptor.name);
|
||||
image = attachment.image;
|
||||
mips = attachment.descriptor.mips;
|
||||
initialLayout = attachment.descriptor.layout;
|
||||
}
|
||||
}
|
||||
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;
|
||||
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(
|
||||
@ -39,24 +56,41 @@ namespace {
|
||||
subresourceRange.baseMipLevel = 0;
|
||||
subresourceRange.levelCount = 1;
|
||||
subresourceRange.baseArrayLayer = 0;
|
||||
subresourceRange.layerCount = 1;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
subresourceRange.layerCount = self->metadata.eyes;
|
||||
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
for ( auto& descriptor : shader.metadata.aliases.attachments ) {
|
||||
if ( descriptor.layout == VK_IMAGE_LAYOUT_UNDEFINED ) continue;
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
size_t mips = 1;
|
||||
|
||||
if ( descriptor.renderMode ) {
|
||||
if ( descriptor.renderMode->hasAttachment(descriptor.name) )
|
||||
image = descriptor.renderMode->getAttachment(descriptor.name).image;
|
||||
if ( descriptor.renderMode->hasAttachment(descriptor.name) ) {
|
||||
auto& attachment = descriptor.renderMode->getAttachment(descriptor.name);
|
||||
image = attachment.image;
|
||||
mips = attachment.descriptor.mips;
|
||||
initialLayout = attachment.descriptor.layout;
|
||||
}
|
||||
|
||||
} else if ( self->hasAttachment(descriptor.name) ) {
|
||||
if ( self->hasAttachment(descriptor.name) )
|
||||
image = self->getAttachment(descriptor.name).image;
|
||||
if ( self->hasAttachment(descriptor.name) ) {
|
||||
auto& attachment = self->getAttachment(descriptor.name);
|
||||
image = attachment.image;
|
||||
mips = attachment.descriptor.mips;
|
||||
initialLayout = attachment.descriptor.layout;
|
||||
}
|
||||
}
|
||||
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;
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -12,8 +12,8 @@
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#define VK_DEBUG_VALIDATION_MESSAGE(x)\
|
||||
// VK_VALIDATION_MESSAGE(x);
|
||||
#define VK_DEBUG_VALIDATION_MESSAGE(...)\
|
||||
//VK_VALIDATION_MESSAGE(__VA_ARGS__);
|
||||
|
||||
#define UF_SHADER_PARSE_AS_JSON 0
|
||||
#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
|
||||
uf::stl::string path = uf::string::join(variableName, ".");
|
||||
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
|
||||
// is strictly an int
|
||||
if ( value.is<int>(true) ) {
|
||||
@ -120,7 +120,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
|
||||
#endif
|
||||
};
|
||||
#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));
|
||||
#endif
|
||||
parse(payload);
|
||||
@ -264,7 +264,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
|
||||
#if UF_SHADER_TRACK_NAMES
|
||||
uf::stl::string path = uf::string::join(variableName, ".");
|
||||
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
|
||||
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];
|
||||
#if UF_SHADER_TRACK_NAMES
|
||||
VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename);
|
||||
VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
|
||||
//VK_VALIDATION_MESSAGE("Updating " << name << " in " << filename);
|
||||
//VK_VALIDATION_MESSAGE("Iterator: " << (void*) byteBuffer << "\t" << (void*) byteBufferEnd << "\t" << (byteBufferEnd - byteBuffer));
|
||||
#endif
|
||||
parseDefinition(payload, definitions);
|
||||
#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
|
||||
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);
|
||||
if ( bufferSize <= 0 ) break;
|
||||
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 = 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();
|
||||
// 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 ) {\
|
||||
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 );\
|
||||
}
|
||||
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;
|
||||
// not a multiple of 4, for some reason
|
||||
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;
|
||||
size *= 4;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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();
|
||||
pushConstant.create( size );
|
||||
@ -724,7 +725,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
specializationMapEntries.emplace_back(specializationMapEntry);
|
||||
}
|
||||
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;
|
||||
size_t offset = 0;
|
||||
@ -798,7 +799,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
definition.validate = false;
|
||||
} break;
|
||||
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;
|
||||
}
|
||||
#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["default"] = member["value"];
|
||||
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
|
||||
|
||||
memcpy( &s[offset], &buffer, size );
|
||||
@ -859,7 +860,7 @@ bool ext::vulkan::Shader::validate() {
|
||||
if ( it == uniforms.end() ) break;
|
||||
auto& uniform = *(it++);
|
||||
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.create(buffer.allocationInfo.size);
|
||||
valid = false;
|
||||
|
||||
@ -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 ( defer ) {
|
||||
ext::vulkan::gc::textures.emplace_back( *this );
|
||||
ext::vulkan::mutex.lock();
|
||||
device->transient.textures.emplace_back(*this);
|
||||
ext::vulkan::mutex.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
if ( view != VK_NULL_HANDLE ) {
|
||||
vkDestroyImageView(device->logicalDevice, view, nullptr);
|
||||
VK_UNREGISTER_HANDLE( view );
|
||||
view = VK_NULL_HANDLE;
|
||||
}
|
||||
if ( image != VK_NULL_HANDLE ) {
|
||||
@ -581,6 +584,7 @@ void ext::vulkan::Texture::fromBuffers(
|
||||
viewCreateInfo.subresourceRange.levelCount = this->mips;
|
||||
viewCreateInfo.image = image;
|
||||
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
|
||||
VK_REGISTER_HANDLE( view );
|
||||
|
||||
{
|
||||
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 mipHeight = height;
|
||||
int32_t mipDepth = depth;
|
||||
int32_t mipDepth = MAX(1, depth);
|
||||
for ( size_t i = 1; i < this->mips; ++i ) {
|
||||
// transition previous layer to read from it
|
||||
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.baseArrayLayer = 0;
|
||||
imageCopy.dstSubresource.layerCount = 1;
|
||||
imageCopy.dstOffset = { 0, 0, 0 };
|
||||
imageCopy.dstOffset = { 0, 0, layerID };
|
||||
imageCopy.extent = { this->width, this->height, 1 };
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "copyImage" );
|
||||
|
||||
@ -116,8 +116,6 @@ uint32_t ext::vulkan::states::frameAccumulate = 0;
|
||||
bool ext::vulkan::states::frameAccumulateReset = false;
|
||||
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;
|
||||
|
||||
ext::vulkan::Buffer ext::vulkan::scratchBuffer;
|
||||
@ -495,6 +493,7 @@ void ext::vulkan::initialize( bool soft ) {
|
||||
void ext::vulkan::tick() {
|
||||
// ext::vulkan::mutex.lock();
|
||||
if ( ext::vulkan::states::resized || ext::vulkan::settings::experimental::rebuildOnTickBegin ) {
|
||||
synchronize(0b11);
|
||||
ext::vulkan::states::rebuild = true;
|
||||
::skip = true;
|
||||
}
|
||||
@ -534,13 +533,6 @@ void ext::vulkan::tick() {
|
||||
|
||||
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;
|
||||
|
||||
ext::vulkan::states::rebuild = false;
|
||||
@ -666,6 +658,9 @@ void ext::vulkan::render() {
|
||||
for ( auto& buffer : transient.buffers ) buffer.destroy(false);
|
||||
transient.buffers.clear();
|
||||
|
||||
for ( auto& texture : transient.textures ) texture.destroy(false);
|
||||
transient.textures.clear();
|
||||
|
||||
for ( auto& as : transient.ass ) {
|
||||
uf::renderer::vkDestroyAccelerationStructureKHR(device, as.handle, nullptr);
|
||||
VK_UNREGISTER_HANDLE( as.handle );
|
||||
@ -677,7 +672,7 @@ void ext::vulkan::destroy( bool soft ) {
|
||||
ext::vulkan::flushCommandBuffers();
|
||||
|
||||
// ext::vulkan::mutex.lock();
|
||||
synchronize();
|
||||
synchronize(0b11);
|
||||
|
||||
#if UF_USE_FFX_FSR
|
||||
if ( settings::pipelines::fsr ) {
|
||||
@ -725,7 +720,7 @@ void ext::vulkan::destroy( bool soft ) {
|
||||
// ext::vulkan::mutex.unlock();
|
||||
|
||||
// check for any leaked resources
|
||||
if ( false ) {
|
||||
if ( ext::vulkan::settings::validation::checkpoints ) {
|
||||
UF_MSG_DEBUG("Leaked resources:");
|
||||
|
||||
for ( auto& resource : ext::vulkan::Resource<VkBuffer_T*>::handles ) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user