diff --git a/bin/data/shaders/base/base.frag.glsl b/bin/data/shaders/base/base.frag.glsl index e8cc6c81..a253ea31 100644 --- a/bin/data/shaders/base/base.frag.glsl +++ b/bin/data/shaders/base/base.frag.glsl @@ -2,6 +2,7 @@ #pragma shader_stage(fragment) #define TEXTURES 1 +#define CUBEMAPS 1 #define MAX_TEXTURES TEXTURES #include "../common/macros.h" #include "../common/structs.h" diff --git a/bin/data/shaders/common/functions.h b/bin/data/shaders/common/functions.h index c33cdf6e..a18ba6da 100644 --- a/bin/data/shaders/common/functions.h +++ b/bin/data/shaders/common/functions.h @@ -12,16 +12,6 @@ vec3 orthogonal(vec3 u){ const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); } -void whitenoise(inout vec3 color, const vec4 parameters) { - const float flicker = parameters.x; - const float pieces = parameters.y; - const float blend = parameters.z; - const float time = parameters.w; - if ( blend < 0.0001 ) return; - const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); - const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); - color = mix( color, vec3(whiteNoise), blend ); -} vec3 decodeNormals( vec2 enc ) { const vec2 ang = enc*2-1; const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); @@ -33,14 +23,12 @@ vec2 encodeNormals( vec3 n ) { // return n.xy/p + 0.5; return (vec2(atan(n.y,n.x)/PI, n.z)+1.0)*0.5; } -float mipLevel( in vec2 uv ) { - const vec2 dx_vtc = dFdx(uv); - const vec2 dy_vtc = dFdy(uv); - return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); -} bool validTextureIndex( int textureIndex ) { return 0 <= textureIndex && textureIndex < MAX_TEXTURES; } +bool validCubemapIndex( int textureIndex ) { + return 0 <= textureIndex && textureIndex < CUBEMAPS; +} vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { const vec3 t0 = (boundsMin - ray.origin) / ray.direction; const vec3 t1 = (boundsMax - ray.origin) / ray.direction; @@ -50,6 +38,28 @@ vec2 rayBoxDst( vec3 boundsMin, vec3 boundsMax, in Ray ray ) { const float tEnd = max(0, min( tmax.x, min(tmax.y, tmax.z) ) - tStart); return vec2(tStart, tEnd); } +#if VXGI +float cascadePower( uint x ) { + return pow(1 + x, ubo.cascadePower); +// return max( 1, x * ubo.cascadePower ); +} +#endif +#if !COMPUTE +void whitenoise(inout vec3 color, const vec4 parameters) { + const float flicker = parameters.x; + const float pieces = parameters.y; + const float blend = parameters.z; + const float time = parameters.w; + if ( blend < 0.0001 ) return; + const float freq = sin(pow(mod(time, flicker) + flicker, 1.9)); + const float whiteNoise = rand2( floor(gl_FragCoord.xy / pieces) + mod(time, freq) ); + color = mix( color, vec3(whiteNoise), blend ); +} +float mipLevel( in vec2 uv ) { + const vec2 dx_vtc = dFdx(uv); + const vec2 dy_vtc = dFdy(uv); + return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc))); +} vec4 resolve( subpassInputMS t, const uint samples ) { vec4 resolved = vec4(0); for ( int i = 0; i < samples; ++i ) resolved += subpassLoad(t, i); @@ -62,6 +72,7 @@ uvec4 resolve( usubpassInputMS t, const uint samples ) { resolved /= uvec4(samples); return resolved; } +#endif vec4 resolve( sampler2DMS t, ivec2 uv ) { vec4 resolved = vec4(0); int samples = textureSamples(t); diff --git a/bin/data/shaders/common/pbr.h b/bin/data/shaders/common/pbr.h index 6dccd9e3..d07ce150 100644 --- a/bin/data/shaders/common/pbr.h +++ b/bin/data/shaders/common/pbr.h @@ -22,7 +22,6 @@ void pbr() { for ( uint i = 0; i < ubo.lights; ++i ) { const Light light = lights[i]; if ( light.power <= LIGHT_POWER_CUTOFF ) continue; - const vec3 Lp = light.position; const vec3 Liu = vec3(ubo.matrices.view[surface.pass] * vec4(light.position, 1)) - surface.position.eye; const vec3 Li = normalize(Liu); const float Ls = shadowFactor( light, 0.0 ); diff --git a/bin/data/shaders/common/shadows.h b/bin/data/shaders/common/shadows.h index 06b2f45d..a645c105 100644 --- a/bin/data/shaders/common/shadows.h +++ b/bin/data/shaders/common/shadows.h @@ -20,15 +20,94 @@ const vec2 poissonDisk[16] = vec2[]( #ifndef SHADOW_SAMPLES #define SHADOW_SAMPLES ubo.shadowSamples #endif +#if VXGI + float voxelShadowFactor( const Light, float def ); +#endif +#if CUBEMAPS +float omniShadowMap( const Light light, float def ) { + return 1.0; +} +#else +float omniShadowMap( const Light light, float def ) { + float factor = 1.0; + + const mat4 views[6] = { + mat4( 0, 0, 1, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 0, 0,-1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0, 1, 0, 0,-1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 0,-1, 0, 0, 1, 0, 0, 0, 0, 0, 1 ), + mat4( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ), + mat4(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0, 1 ), + }; + + const vec3 D = normalize(surface.position.world - light.position); + const vec3 N = abs(D); + uint A = N.y > N.x ? 1 : 0; + A = N.z > N[A] ? 2 : A; + uint index = A * 2; + if ( D[A] < 0.0 ) ++index; + + vec4 positionClip = light.projection * views[index] * vec4(surface.position.world - light.position, 1.0); + positionClip.xy /= positionClip.w; + + if ( positionClip.x < -1 || positionClip.x >= 1 ) return 0.0; + if ( positionClip.y < -1 || positionClip.y >= 1 ) return 0.0; + if ( positionClip.z < -1 || positionClip.z >= 1 ) return 0.0; + + const float eyeDepthScale = 1.0; + const float sampledDepthScale = light.view[1][1]; // light view matricies will incorporate scaling factors for some retarded reason, so we need to rescale it by grabbing from here, hopefully it remains coherent between all light matrices to ever exist in engine + + const float bias = light.depthBias; + const float eyeDepth = abs(positionClip.z / positionClip.w) * eyeDepthScale; + + const vec3 sampleOffsetDirections[20] = { + vec3( 1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3( 1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3( 1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3( 1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3( 0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) + }; + + float sampled = 0; + const int samples = int(SHADOW_SAMPLES); + if ( light.typeMap == 1 ) { + if ( samples < 1 ) { + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + vec2 poisson = poissonDisk[idx] / 700.0; + vec3 P = vec3( poisson.xy, (poisson.x + poisson.y) * 0.5 ); + sampled = texture(samplerCubemaps[nonuniformEXT(light.indexMap)], D + P ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + } else if ( light.typeMap == 2 ) { + const vec2 uv = positionClip.xy * 0.5 + 0.5; + if ( samples < 1 ) { + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv).r * sampledDepthScale; + } else { + for ( int i = 0; i < samples; ++i ) { + const int idx = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; + sampled = texture(samplerTextures[nonuniformEXT(light.indexMap + index)], uv + poissonDisk[idx] / 700.0 ).r * sampledDepthScale; + if ( eyeDepth < sampled - bias ) factor -= 1.0 / samples; + } + return factor; + } + } + return eyeDepth < sampled - bias ? 0.0 : factor; +} +#endif float shadowFactor( const Light light, float def ) { - if ( !validTextureIndex(light.mapIndex) ) { + if ( light.typeMap != 0 ) return omniShadowMap( light, def ); + if ( !validTextureIndex(light.indexMap) ) #if VXGI return voxelShadowFactor( light, def ); #else return 1.0; #endif - } vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); positionClip.xyz /= positionClip.w; @@ -54,10 +133,10 @@ float shadowFactor( const Light light, float def ) { const float bias = light.depthBias; const float eyeDepth = positionClip.z; const int samples = int(SHADOW_SAMPLES); - if ( samples < 1 ) return eyeDepth < texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv).r - bias ? 0.0 : factor; + if ( samples < 1 ) return eyeDepth < texture(samplerTextures[nonuniformEXT(light.indexMap)], uv).r - bias ? 0.0 : factor; for ( int i = 0; i < samples; ++i ) { const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; - const float lightDepth = texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv + poissonDisk[index] / 700.0 ).r; + const float lightDepth = texture(samplerTextures[nonuniformEXT(light.indexMap)], uv + poissonDisk[index] / 700.0 ).r; if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; } return factor; diff --git a/bin/data/shaders/common/structs.h b/bin/data/shaders/common/structs.h index f579bd9f..fe977013 100644 --- a/bin/data/shaders/common/structs.h +++ b/bin/data/shaders/common/structs.h @@ -59,9 +59,9 @@ struct Light { float power; int type; - int mapIndex; + int typeMap; + int indexMap; float depthBias; - float padding; mat4 view; mat4 projection; @@ -135,4 +135,13 @@ struct Voxel { vec3 normal; vec2 uv; vec4 color; -}; \ No newline at end of file +}; + +struct VoxelInfo { + vec3 min; + vec3 max; + + float mipmapLevels; + float radianceSize; + float radianceSizeRecip; +} voxelInfo; \ No newline at end of file diff --git a/bin/data/shaders/common/vxgi.h b/bin/data/shaders/common/vxgi.h index b6d7eaf5..98622a7c 100644 --- a/bin/data/shaders/common/vxgi.h +++ b/bin/data/shaders/common/vxgi.h @@ -1,16 +1,4 @@ // GI -struct VoxelInfo { - vec3 min; - vec3 max; - - float mipmapLevels; - float radianceSize; - float radianceSizeRecip; -} voxelInfo; -float cascadePower( uint x ) { - return pow(1 + x, ubo.cascadePower); -// return max( 1, x * ubo.cascadePower ); -} uint cascadeIndex( vec3 v ) { float x = max3( abs( v ) ); for ( uint cascade = 0; cascade < CASCADES; ++cascade ) @@ -82,7 +70,7 @@ vec4 voxelTrace( inout Ray ray, float maxDistance ) { } uint voxelShadowsCount = 0; float voxelShadowFactor( const Light light, float def ) { - if ( voxelShadowsCount++ > ubo.shadowSamples ) return 1.0; + if ( voxelShadowsCount++ > ubo.vxgiShadowSamples ) return 1.0; const float SHADOW_APERTURE = 0.2; const float DEPTH_BIAS = 0.0; diff --git a/bin/data/shaders/display/rendertarget.frag.glsl b/bin/data/shaders/display/rendertarget.frag.glsl index d434b200..ab078cc0 100644 --- a/bin/data/shaders/display/rendertarget.frag.glsl +++ b/bin/data/shaders/display/rendertarget.frag.glsl @@ -3,6 +3,7 @@ #extension GL_EXT_samplerless_texture_functions : require #define TEXTURES 1 +#define CUBEMAPS 1 #define DEFERRED_SAMPLING 0 #include "../common/macros.h" diff --git a/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl b/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl index eb017ad4..0728d016 100644 --- a/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl +++ b/bin/data/shaders/display/rendertarget.no-msaa.frag.glsl @@ -3,6 +3,7 @@ #extension GL_EXT_samplerless_texture_functions : require #define TEXTURES 1 +#define CUBEMAPS 1 #define DEFERRED_SAMPLING 0 #define MULTISAMPLING 0 diff --git a/bin/data/shaders/display/subpass.frag.glsl b/bin/data/shaders/display/subpass.frag.glsl index 2c7941d3..9db4ce44 100644 --- a/bin/data/shaders/display/subpass.frag.glsl +++ b/bin/data/shaders/display/subpass.frag.glsl @@ -5,10 +5,6 @@ void main() { populateSurface(); - - const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion; - surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - - pbr(); + directLighting(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.h b/bin/data/shaders/display/subpass.h index a1368c05..6c01a6d6 100644 --- a/bin/data/shaders/display/subpass.h +++ b/bin/data/shaders/display/subpass.h @@ -5,8 +5,9 @@ #include "../common/macros.h" layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; #if VXGI - layout (constant_id = 1) const uint CASCADES = 16; + layout (constant_id = 2) const uint CASCADES = 16; #endif #if !MULTISAMPLING @@ -49,6 +50,11 @@ layout (binding = 4) uniform UBO { uint msaa; uint shadowSamples; float cascadePower; + + uint indexSkybox; + uint vxgiShadowSamples; + float pointLightEyeDepthScale; + uint padding2; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -64,33 +70,29 @@ layout (std140, binding = 8) readonly buffer DrawCalls { DrawCall drawCalls[]; }; +layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 10) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 11) uniform sampler3D samplerNoise; #if VXGI - layout (binding = 9) uniform usampler3D voxelId[CASCADES]; - layout (binding = 10) uniform sampler3D voxelUv[CASCADES]; - layout (binding = 11) uniform sampler3D voxelNormal[CASCADES]; - layout (binding = 12) uniform sampler3D voxelRadiance[CASCADES]; - - layout (binding = 13) uniform sampler3D samplerNoise; - layout (binding = 14) uniform samplerCube samplerSkybox; - layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES]; -#else - layout (binding = 9) uniform sampler3D samplerNoise; - layout (binding = 10) uniform samplerCube samplerSkybox; - layout (binding = 11) uniform sampler2D samplerTextures[TEXTURES]; + layout (binding = 12) uniform usampler3D voxelId[CASCADES]; + layout (binding = 13) uniform sampler3D voxelUv[CASCADES]; + layout (binding = 14) uniform sampler3D voxelNormal[CASCADES]; + layout (binding = 15) uniform sampler3D voxelRadiance[CASCADES]; #endif layout (location = 0) in vec2 inUv; layout (location = 1) in flat uint inPushConstantPass; layout (location = 0) out vec4 outFragColor; +layout (location = 1) out vec4 outDebugColor; #include "../common/functions.h" #include "../common/fog.h" #include "../common/pbr.h" +#include "../common/shadows.h" #if VXGI #include "../common/vxgi.h" #endif -#include "../common/shadows.h" void postProcess() { #if FOG @@ -165,7 +167,7 @@ void populateSurface() { surface.normal.eye = vec3( ubo.matrices.view[surface.pass] * vec4(surface.normal.world, 0.0) ); if ( ID.x == 0 || ID.y == 0 ) { - surface.fragment.rgb = texture( samplerSkybox, surface.ray.direction ).rgb; + surface.fragment.rgb = texture( samplerCubemaps[ubo.indexSkybox], surface.ray.direction ).rgb; surface.fragment.a = 0.0; postProcess(); return; @@ -216,4 +218,17 @@ void populateSurface() { surface.material.roughness = material.factorRoughness; surface.material.occlusion = material.factorOcclusion; surface.material.indexLightmap = material.indexLightmap; +} + +void directLighting() { + const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; + surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); + +#if PBR + pbr(); +#elif LAMBERT + lambert(); +#elif PHONG + phong(); +#endif } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.no-msaa.frag.glsl b/bin/data/shaders/display/subpass.no-msaa.frag.glsl index b4eafa74..0ded387d 100644 --- a/bin/data/shaders/display/subpass.no-msaa.frag.glsl +++ b/bin/data/shaders/display/subpass.no-msaa.frag.glsl @@ -6,10 +6,6 @@ void main() { populateSurface(); - - const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion; - surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - - pbr(); + directLighting(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vxgi.frag.glsl b/bin/data/shaders/display/subpass.vxgi.frag.glsl index e8a51e8c..b39fc34d 100644 --- a/bin/data/shaders/display/subpass.vxgi.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.frag.glsl @@ -2,16 +2,11 @@ #pragma shader_stage(fragment) #define VXGI 1 - #include "./subpass.h" void main() { populateSurface(); indirectLighting(); - - const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; - surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - - pbr(); + directLighting(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl b/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl index ea9f608d..8a70b9ae 100644 --- a/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl +++ b/bin/data/shaders/display/subpass.vxgi.no-msaa.frag.glsl @@ -8,10 +8,6 @@ void main() { populateSurface(); indirectLighting(); - - const vec3 ambient = ubo.ambient.rgb * surface.material.occlusion + surface.material.indirect.rgb; - surface.fragment.rgb += (0 <= surface.material.indexLightmap) ? (surface.material.albedo.rgb + ambient) : (surface.material.albedo.rgb * ambient); - - pbr(); + directLighting(); postProcess(); } \ No newline at end of file diff --git a/bin/data/shaders/display/vxgi.comp.glsl b/bin/data/shaders/display/vxgi.comp.glsl index 5fe1e751..1f7cffb3 100644 --- a/bin/data/shaders/display/vxgi.comp.glsl +++ b/bin/data/shaders/display/vxgi.comp.glsl @@ -11,136 +11,15 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 8) in; #define LAMBERT 1 #define PBR 0 +#define VXGI 1 +#define COMPUTE 1 -const float PI = 3.14159265359; -const float EPSILON = 0.00001; +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CUBEMAPS = 128; +layout (constant_id = 2) const uint CASCADES = 16; -const float LIGHT_POWER_CUTOFF = 0.005; - -layout (constant_id = 0) const uint CASCADES = 16; -layout (constant_id = 1) const uint TEXTURES = 512; - -struct Matrices { - mat4 view[2]; - mat4 projection[2]; - mat4 iView[2]; - mat4 iProjection[2]; - mat4 iProjectionView[2]; - vec4 eyePos[2]; - mat4 vxgi; -}; - -struct Space { - vec3 eye; - vec3 world; -}; - -struct Ray { - vec3 origin; - vec3 direction; - - vec3 position; - float distance; -}; - -struct Fog { - vec3 color; - float stepScale; - - vec3 offset; - float densityScale; - - float densityThreshold; - float densityMultiplier; - float absorbtion; - float padding1; - - vec2 range; - float padding2; - float padding3; -}; - -struct Mode { - uint type; - uint scalar; - vec2 padding; - vec4 parameters; -}; - -struct Light { - vec3 position; - float radius; - - vec3 color; - float power; - - int type; - int mapIndex; - float depthBias; - float padding; - - mat4 view; - mat4 projection; -}; - -struct Material { - vec4 colorBase; - vec4 colorEmissive; - - float factorMetallic; - float factorRoughness; - float factorOcclusion; - float factorAlphaCutoff; - - int indexAlbedo; - int indexNormal; - int indexEmissive; - int indexOcclusion; - - int indexMetallicRoughness; - int indexAtlas; - int indexLightmap; - int modeAlpha; -}; - -struct Texture { - int index; - int samp; - int remap; - float blend; - - vec4 lerp; -}; - -struct DrawCall { - int materialIndex; - uint materials; - int textureIndex; - uint textures; -}; - -struct SurfaceMaterial { - uint id; - - vec4 albedo; - vec4 indirect; - - float metallic; - float roughness; - float occlusion; -}; - -struct Surface { - vec2 uv; - Space position; - Space normal; - - Ray ray; - - SurfaceMaterial material; - - vec4 fragment; -} surface; +#include "../common/macros.h" +#include "../common/structs.h" layout (binding = 4) uniform UBO { Matrices matrices; @@ -160,6 +39,11 @@ layout (binding = 4) uniform UBO { uint msaa; uint shadowSamples; float cascadePower; + + uint indexSkybox; + uint vxgiShadowSamples; + float pointLightEyeDepthScale; + uint padding2; } ubo; layout (std140, binding = 5) readonly buffer Lights { @@ -175,122 +59,22 @@ layout (std140, binding = 8) readonly buffer DrawCalls { DrawCall drawCalls[]; }; -layout (binding = 9, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; -layout (binding = 10, rg16f) uniform volatile coherent image3D voxelUv[CASCADES]; -layout (binding = 11, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; +layout (binding = 9) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 10) uniform samplerCube samplerCubemaps[CUBEMAPS]; +layout (binding = 11) uniform sampler3D samplerNoise; + +layout (binding = 12, rg16ui) uniform volatile coherent uimage3D voxelId[CASCADES]; +layout (binding = 13, rg16f) uniform volatile coherent image3D voxelUv[CASCADES]; +layout (binding = 14, rg16f) uniform volatile coherent image3D voxelNormal[CASCADES]; #if VXGI_HDR - layout (binding = 12, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; + layout (binding = 15, rgba8) uniform volatile coherent image3D voxelRadiance[CASCADES]; #else - layout (binding = 12, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; + layout (binding = 15, rgba16f) uniform volatile coherent image3D voxelRadiance[CASCADES]; #endif -layout (binding = 13) uniform sampler3D samplerNoise; -layout (binding = 14) uniform samplerCube samplerSkybox; -layout (binding = 15) uniform sampler2D samplerTextures[TEXTURES]; - -// GGX/Towbridge-Reitz normal distribution function. -// Uses Disney's reparametrization of alpha = roughness^2. -float ndfGGX(float cosLh, float roughness) { - const float alpha = roughness * roughness; - const float alphaSq = alpha * alpha; - const float denom = (cosLh * cosLh) * (alphaSq - 1.0) + 1.0; - return alphaSq / (PI * denom * denom); -} - -// Single term for separable Schlick-GGX below. -float gaSchlickG1(float cosTheta, float k) { - return cosTheta / (cosTheta * (1.0 - k) + k); -} - -// Schlick-GGX approximation of geometric attenuation function using Smith's method. -float gaSchlickGGX(float cosLi, float cosLo, float roughness) { - const float r = roughness + 1.0; - const float k = (r * r) / 8.0; // Epic suggests using this roughness remapping for analytic lights. - return gaSchlickG1(cosLi, k) * gaSchlickG1(cosLo, k); -} -vec3 fresnelSchlick(vec3 F0, float cosTheta) { - return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0); -} - -float random(vec3 seed, int i){ - return fract(sin(dot(vec4(seed,i), vec4(12.9898,78.233,45.164,94.673))) * 43758.5453); -} - -// Returns a vector that is orthogonal to u. -vec3 orthogonal(vec3 u){ - u = normalize(u); - const vec3 v = vec3(0.99146, 0.11664, 0.05832); // Pick any normalized vector. - return abs(dot(u, v)) > 0.99999f ? cross(u, vec3(0, 1, 0)) : cross(u, v); -} -float rand2(vec2 co){ - return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 143758.5453); -} -float rand3(vec3 co){ - return fract(sin(dot(co.xyz ,vec3(12.9898,78.233, 37.719))) * 143758.5453); -} - -vec3 gamma( vec3 i ) { - return pow(i.rgb, vec3(1.0 / 2.2)); -} - -vec3 decodeNormals( vec2 enc ) { - const vec2 ang = enc*2-1; - const vec2 scth = vec2( sin(ang.x * PI), cos(ang.x * PI) ); - const vec2 scphi = vec2(sqrt(1.0 - ang.y*ang.y), ang.y); - return normalize( vec3(scth.y*scphi.x, scth.x*scphi.x, scphi.y) ); -} -float wrap( float i ) { - return fract(i); -} -vec2 wrap( vec2 uv ) { - return vec2( wrap( uv.x ), wrap( uv.y ) ); -} -bool validTextureIndex( int textureIndex ) { - return 0 <= textureIndex; // && textureIndex < ubo.textures; -} - -float shadowFactor( const Light light, float def ) { - if ( !validTextureIndex(light.mapIndex) ) return 1.0; - - vec4 positionClip = light.projection * light.view * vec4(surface.position.world, 1.0); - positionClip.xyz /= positionClip.w; - - if ( positionClip.x < -1 || positionClip.x >= 1 ) return def; //0.0; - if ( positionClip.y < -1 || positionClip.y >= 1 ) return def; //0.0; - if ( positionClip.z <= 0 || positionClip.z >= 1 ) return def; //0.0; - - float factor = 1.0; - - // spot light - if ( abs(light.type) == 2 || abs(light.type) == 3 ) { - const float dist = length( positionClip.xy ); - if ( dist > 0.5 ) return def; //0.0; - - // spot light with attenuation - if ( abs(light.type) == 3 ) { - factor = 1.0 - (pow(dist * 2,2.0)); - } - } - - const vec2 uv = positionClip.xy * 0.5 + 0.5; - const float bias = light.depthBias; - const float eyeDepth = positionClip.z; - const int samples = int(ubo.shadowSamples); - return eyeDepth < texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv).r - bias ? 0.0 : factor; -#if 0 - for ( int i = 0; i < samples; ++i ) { - const int index = int( float(samples) * random(floor(surface.position.world.xyz * 1000.0), i)) % samples; - const float lightDepth = texture(samplerTextures[nonuniformEXT(light.mapIndex)], uv + poissonDisk[index] / 700.0 ).r; - if ( eyeDepth < lightDepth - bias ) factor -= 1.0 / samples; - } - return factor; -#endif -} - -float cascadePower( uint x ) { - return pow(1 + x, ubo.cascadePower); -// return max( 1, x * ubo.cascadePower ); -} +#include "../common/functions.h" +#undef VXGI +#include "../common/shadows.h" void main() { const vec3 tUvw = gl_GlobalInvocationID.xzy; diff --git a/bin/data/shaders/gltf/baked.frag.glsl b/bin/data/shaders/gltf/baked.frag.glsl index 0ed0bf30..766faf9f 100644 --- a/bin/data/shaders/gltf/baked.frag.glsl +++ b/bin/data/shaders/gltf/baked.frag.glsl @@ -1,6 +1,7 @@ #version 450 #pragma shader_stage(fragment) +#define CUBEMAPS 1 #define MAX_TEXTURES TEXTURES layout (constant_id = 0) const uint TEXTURES = 1; diff --git a/bin/data/shaders/gltf/baking/bake.frag.glsl b/bin/data/shaders/gltf/baking/bake.frag.glsl index a18d2a2c..d814bdb4 100644 --- a/bin/data/shaders/gltf/baking/bake.frag.glsl +++ b/bin/data/shaders/gltf/baking/bake.frag.glsl @@ -10,6 +10,7 @@ layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; #define PBR 0 #define LAMBERT 1 +#define CUBEMAPS 1 #include "../../common/macros.h" #include "../../common/structs.h" diff --git a/bin/data/shaders/gltf/base.frag.glsl b/bin/data/shaders/gltf/base.frag.glsl index 23e96c31..dfa888d9 100644 --- a/bin/data/shaders/gltf/base.frag.glsl +++ b/bin/data/shaders/gltf/base.frag.glsl @@ -3,6 +3,7 @@ #extension GL_EXT_nonuniform_qualifier : enable +#define CUBEMAPS 1 #define MAX_TEXTURES textures.length() layout (constant_id = 0) const uint TEXTURES = 1; diff --git a/bin/data/shaders/gltf/voxelize.frag.glsl b/bin/data/shaders/gltf/voxelize.frag.glsl index 1a8a5369..8ec9a1dd 100644 --- a/bin/data/shaders/gltf/voxelize.frag.glsl +++ b/bin/data/shaders/gltf/voxelize.frag.glsl @@ -4,9 +4,10 @@ #define BLEND 1 #define DEPTH_TEST 1 +#define CUBEMAPS 1 -layout (constant_id = 0) const uint CASCADES = 16; -layout (constant_id = 1) const uint TEXTURES = 512; +layout (constant_id = 0) const uint TEXTURES = 512; +layout (constant_id = 1) const uint CASCADES = 16; #define MAX_TEXTURES textures.length() #include "../common/macros.h" diff --git a/bin/data/shaders/gui/base.frag.glsl b/bin/data/shaders/gui/base.frag.glsl index 6ac4c46b..8eb1eeb7 100644 --- a/bin/data/shaders/gui/base.frag.glsl +++ b/bin/data/shaders/gui/base.frag.glsl @@ -2,6 +2,7 @@ #pragma shader_stage(fragment) #define TEXTURES 1 +#define CUBEMAPS 1 #define DEFERRED_SAMPLING 0 #include "../common/macros.h" diff --git a/bin/data/shaders/gui/text.frag.glsl b/bin/data/shaders/gui/text.frag.glsl index b7b595ee..14d2a79c 100644 --- a/bin/data/shaders/gui/text.frag.glsl +++ b/bin/data/shaders/gui/text.frag.glsl @@ -2,6 +2,7 @@ #pragma shader_stage(fragment) #define TEXTURES 1 +#define CUBEMAPS 1 #define DEFERRED_SAMPLING 0 #include "../common/macros.h" diff --git a/client/main.cpp b/client/main.cpp index d9d86b16..4d2c258f 100644 --- a/client/main.cpp +++ b/client/main.cpp @@ -20,7 +20,11 @@ int main(int argc, char** argv){ std::atexit([]{ uf::iostream << "Termination via std::atexit()!" << "\n"; - client::terminated = !(client::ready = ext::ready = false); + ext::ready = false; + client::ready = false; + client::terminated = true; + ext::terminate(); + client::terminate(); }); client::initialize(); @@ -46,19 +50,12 @@ int main(int argc, char** argv){ std::string hook = "window:Resized"; json["type"] = hook; json["invoker"] = "ext"; - json["window"]["size"] = client::config["window"]["size"]; - // json["window"]["size"]["x"] = client::config["window"]["size"]["x"]; - // json["window"]["size"]["y"] = client::config["window"]["size"]["y"]; uf::hooks.call(hook, json); } #if UF_ENV_DREAMCAST - // UF_TIMER_MULTITRACE_START("==== START FRAME ===="); ext::render(); - // UF_TIMER_MULTITRACE("RENDER"); ext::tick(); - // UF_TIMER_MULTITRACE("TICK"); - // UF_TIMER_MULTITRACE_END("==== END FRAME ===="); #else client::render(); ext::render(); @@ -81,8 +78,8 @@ int main(int argc, char** argv){ } if ( !client::terminated ) { uf::iostream << "Natural termination!" << "\n"; + ext::terminate(); + client::terminate(); } - ext::terminate(); - client::terminate(); return 0; } \ No newline at end of file diff --git a/engine/inc/uf/ext/gltf/pod.h b/engine/inc/uf/ext/gltf/pod.h index bd8bbf72..0cb9b0cf 100644 --- a/engine/inc/uf/ext/gltf/pod.h +++ b/engine/inc/uf/ext/gltf/pod.h @@ -40,9 +40,9 @@ namespace pod { alignas(16) pod::Vector4f color; alignas(4) int32_t type = 0; - alignas(4) int32_t mapIndex = -1; + alignas(4) int32_t typeMap = 0; + alignas(4) int32_t indexMap = -1; alignas(4) float depthBias = 0; - alignas(4) float padding = 0; alignas(16) pod::Matrix4f view; alignas(16) pod::Matrix4f projection; diff --git a/engine/inc/uf/ext/vulkan/rendertarget.h b/engine/inc/uf/ext/vulkan/rendertarget.h index 52c082c5..8279225e 100644 --- a/engine/inc/uf/ext/vulkan/rendertarget.h +++ b/engine/inc/uf/ext/vulkan/rendertarget.h @@ -19,6 +19,7 @@ namespace ext { VkImage image; VkDeviceMemory mem; VkImageView view; + std::vector views; VmaAllocation allocation; VmaAllocationInfo allocationInfo; VkPipelineColorBlendAttachmentState blendState; @@ -28,6 +29,7 @@ namespace ext { struct Subpass { VkPipelineStageFlags stage; VkAccessFlags access; + uint8_t layer; bool autoBuildPipeline; std::vector colors; @@ -47,7 +49,7 @@ namespace ext { // RAII void initialize( Device& device ); void destroy(); - void addPass( VkPipelineStageFlags, VkAccessFlags, const std::vector&, const std::vector&, const std::vector&, size_t, bool = true ); + void addPass( VkPipelineStageFlags, VkAccessFlags, const std::vector&, const std::vector&, const std::vector&, size_t, size_t = 0, bool = true ); size_t attach( const Attachment::Descriptor& descriptor, Attachment* attachment = NULL ); }; } diff --git a/engine/inc/uf/ext/vulkan/texture.h b/engine/inc/uf/ext/vulkan/texture.h index c9c79e6c..871d38ed 100644 --- a/engine/inc/uf/ext/vulkan/texture.h +++ b/engine/inc/uf/ext/vulkan/texture.h @@ -113,6 +113,7 @@ namespace ext { void asRenderTarget( Device& device, uint32_t texWidth, uint32_t texHeight, VkFormat format = VK_FORMAT_R8G8B8A8_UNORM ); void aliasTexture( const Texture& ); void aliasAttachment( const RenderTarget::Attachment& attachment, bool = true ); + void aliasAttachment( const RenderTarget::Attachment& attachment, size_t, bool = true ); void update( uf::Image& image, VkImageLayout, uint32_t layer = 1 ); void update( void*, VkDeviceSize, VkImageLayout, uint32_t layer = 1 ); diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 00be4e2b..2cf8f7be 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -92,29 +92,41 @@ namespace { #if UF_USE_VULKAN { auto& shader = graphic.material.getShader("fragment", "vxgi"); + /* struct SpecializationConstant { - uint32_t cascades = 16; uint32_t textures = 1; + uint32_t cascades = 16; }; auto& specializationConstants = shader.specializationConstants.get(); specializationConstants.textures = texture2Ds; - specializationConstants.cascades = texture3Ds / 4; // 5; - ext::json::forEach( shader.metadata["specializationConstants"], [&]( ext::json::Value& sc ){ + specializationConstants.cascades = texture3Ds / 4; + */ + uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + size_t maxTextures = texture2Ds; + size_t maxCascades = texture3Ds / 4; + + ext::json::forEach( shader.metadata["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ std::string name = sc["name"].as(); - if ( name == "TEXTURES" ) sc["value"] = specializationConstants.textures; - else if ( name == "CASCADES" ) sc["value"] = specializationConstants.cascades; + if ( name == "TEXTURES" ) { + sc["value"] = (specializationConstants[i] = maxTextures); + // sc["value"] = specializationConstants.textures; + } + else if ( name == "CASCADES" ) { + sc["value"] = (specializationConstants[i] = maxCascades); + // sc["value"] = specializationConstants.cascades; + } }); ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ size_t binding = t["binding"].as(); std::string name = t["name"].as(); for ( auto& layout : shader.descriptorSetLayoutBindings ) { if ( layout.binding != binding ) continue; - if ( name == "samplerTextures" ) layout.descriptorCount = specializationConstants.textures; - else if ( name == "voxelId" ) layout.descriptorCount = specializationConstants.cascades; - else if ( name == "voxelUv" ) layout.descriptorCount = specializationConstants.cascades; - else if ( name == "voxelNormal" ) layout.descriptorCount = specializationConstants.cascades; - else if ( name == "voxelRadiance" ) layout.descriptorCount = specializationConstants.cascades; - // else if ( name == "voxelDepth" ) layout.descriptorCount = specializationConstants.cascades; + if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures; + else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; + else if ( name == "voxelRadiance" ) layout.descriptorCount = maxCascades; + // else if ( name == "voxelDepth" ) layout.descriptorCount = maxCascades; } }); } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index 24055f23..d5ab01b0 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -12,7 +12,7 @@ #include #define VK_DEBUG_VALIDATION_MESSAGE(x)\ - //VK_VALIDATION_MESSAGE(x); +// VK_VALIDATION_MESSAGE(x); namespace { uint32_t VERTEX_BUFFER_BIND_ID = 0; @@ -239,6 +239,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des void* s = (void*) shader.specializationConstants; size_t len = shader.specializationConstants.data().len; + bool invalidated = true; for ( size_t i = 0; i < len / 4; ++i ) { auto& payload = shader.metadata["specializationConstants"][i]; std::string type = payload["type"].as(); @@ -248,6 +249,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des if ( payload["validate"].as() && v == 0 ) { VK_DEBUG_VALIDATION_MESSAGE("Specialization constant of 0 for `" << payload.dump() << "` for shader `" << shader.filename << "`"); v = payload["value"].is() ? payload["value"].as() : payload["default"].as(); + invalidated = true; } payload["value"] = v; } else if ( type == "uint32_t" ) { @@ -256,6 +258,7 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des if ( payload["validate"].as() && v == 0 ) { VK_DEBUG_VALIDATION_MESSAGE("Specialization constant of 0 for `" << payload.dump() << "` for shader `" << shader.filename << "`"); v = payload["value"].is() ? payload["value"].as() : payload["default"].as(); + invalidated = true; } payload["value"] = v; } else if ( type == "float" ) { @@ -264,21 +267,23 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic, GraphicDescriptor& des if ( payload["validate"].as() && v == 0 ) { VK_DEBUG_VALIDATION_MESSAGE("Specialization constant of 0 for `" << payload.dump() << "` for shader `" << shader.filename << "`"); v = payload["value"].is() ? payload["value"].as() : payload["default"].as(); + invalidated = true; } payload["value"] = v; } } VK_DEBUG_VALIDATION_MESSAGE("Specialization constants for shader `" << shader.filename << "`: " << shader.metadata["specializationConstants"].dump(1, '\t')); - - - { - shader.specializationInfo = {}; - shader.specializationInfo.mapEntryCount = shader.specializationMapEntries.size(); + if ( invalidated ) { + // shader.specializationInfo = {}; + // shader.specializationInfo.mapEntryCount = shader.specializationMapEntries.size(); shader.specializationInfo.pMapEntries = shader.specializationMapEntries.data(); shader.specializationInfo.pData = (void*) shader.specializationConstants; - shader.specializationInfo.dataSize = shader.specializationConstants.data().len; + // shader.specializationInfo.dataSize = shader.specializationConstants.data().len; shader.descriptor.pSpecializationInfo = &shader.specializationInfo; } + + VK_DEBUG_VALIDATION_MESSAGE("Specialization constants for shader `" << shader.filename << "`: " << shader.specializationInfo.dataSize ); + shaderDescriptors.push_back(shader.descriptor); } @@ -371,7 +376,13 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip struct { std::vector uniform; std::vector storage; + std::vector image; + std::vector image2D; + std::vector imageCube; + std::vector image3D; + std::vector imageUnknown; + std::vector sampler; std::vector input; } infos; @@ -380,8 +391,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip auto& subpass = renderTarget.passes[descriptor.subpass]; for ( auto& input : subpass.inputs ) { infos.input.push_back(ext::vulkan::initializers::descriptorImageInfo( - renderTarget.attachments[input.attachment].view, - // input.layout + renderTarget.attachments[input.attachment].views[subpass.layer], input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout )); } @@ -390,13 +400,26 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip { for ( auto& texture : graphic.material.textures ) { infos.image.emplace_back(texture.descriptor); + switch ( texture.viewType ) { + case VK_IMAGE_VIEW_TYPE_2D: + infos.image2D.emplace_back(texture.descriptor); + break; + case VK_IMAGE_VIEW_TYPE_CUBE: + infos.imageCube.emplace_back(texture.descriptor); + break; + case VK_IMAGE_VIEW_TYPE_3D: + infos.image3D.emplace_back(texture.descriptor); + break; + default: + infos.imageUnknown.emplace_back(texture.descriptor); + break; + } } - for ( auto& sampler : graphic.material.samplers ) { - infos.sampler.emplace_back(sampler.descriptor.info); - } + for ( auto& sampler : graphic.material.samplers ) infos.sampler.emplace_back(sampler.descriptor.info); } - ext::json::Value bindingMapping; + size_t consumes = 0; + std::vector types; for ( auto* shaderPointer : shaders ) { auto& shader = *shaderPointer; @@ -413,8 +436,6 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip PARSE_BUFFER(graphic.buffers) // check if we can even consume that many infos - size_t consumes = 0; - std::vector types; for ( auto& layout : shader.descriptorSetLayoutBindings ) { switch ( layout.descriptorType ) { // consume an texture image info @@ -422,43 +443,57 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: { consumes += layout.descriptorCount; - std::string imageType = ""; std::string binding = std::to_string(layout.binding); - for ( auto* shaderPointer : shaders ) { - auto& shader = *shaderPointer; - - auto& info = shader.metadata["definitions"]["textures"][binding]; - if ( ext::json::isNull(info) ) continue; - imageType = info["type"].as(); - break; - } + std::string imageType = shader.metadata["definitions"]["textures"][binding]["type"].as(); types.reserve(consumes); for ( size_t i = 0; i < layout.descriptorCount; ++i ) types.emplace_back(imageType); } break; } } - for ( size_t i = infos.image.size(); i < consumes; ++i ) { - std::string type = i < types.size() ? types[i] : ""; - if ( type == "3D" ) { - infos.image.push_back(Texture3D::empty.descriptor); - } else if ( type == "Cube" ) { - infos.image.push_back(TextureCube::empty.descriptor); - } else { - infos.image.push_back(Texture2D::empty.descriptor); - } - } + } + + size_t maxTextures2D = 0; + size_t maxTextures3D = 0; + size_t maxTexturesCube = 0; + size_t maxTexturesUnknown = 0; + for ( auto& type : types ) { + if ( type == "3D" ) ++maxTextures3D; + else if ( type == "Cube" ) ++maxTexturesCube; + else if ( type == "2D" ) ++maxTextures2D; + else ++maxTexturesUnknown; } + while ( infos.image2D.size() < maxTextures2D ) infos.image2D.push_back(Texture2D::empty.descriptor); + while ( infos.imageCube.size() < maxTexturesCube ) infos.imageCube.push_back(TextureCube::empty.descriptor); + while ( infos.image3D.size() < maxTextures3D ) infos.image3D.push_back(Texture3D::empty.descriptor); + while ( infos.imageUnknown.size() < maxTexturesUnknown ) infos.imageUnknown.push_back(Texture2D::empty.descriptor); + + for ( size_t i = infos.image.size(); i < consumes; ++i ) { + std::string type = i < types.size() ? types[i] : ""; + if ( type == "3D" ) infos.image.push_back(Texture3D::empty.descriptor); + else if ( type == "Cube" ) infos.image.push_back(TextureCube::empty.descriptor); + else if ( type == "2D" ) infos.image.push_back(Texture2D::empty.descriptor); + else infos.image.push_back(Texture2D::empty.descriptor); + } + auto uniformBufferInfo = infos.uniform.begin(); auto storageBufferInfo = infos.storage.begin(); + auto imageInfo = infos.image.begin(); + auto image2DInfo = infos.image2D.begin(); + auto imageCubeInfo = infos.imageCube.begin(); + auto image3DInfo = infos.image3D.begin(); + auto imageUnknownInfo = infos.imageUnknown.begin(); + auto samplerInfo = infos.sampler.begin(); auto inputInfo = infos.input.begin(); + #define BREAK_ASSERT(condition, ...) if ( condition ) { VK_VALIDATION_MESSAGE(#condition << "\t" << __VA_ARGS__); break; } std::vector writeDescriptorSets; for ( auto* shaderPointer : shaders ) { auto& shader = *shaderPointer; + // UF_DEBUG_MSG(shader.filename << ": "); // UF_DEBUG_MSG("\tAVAILABLE UNIFORM BUFFERS: " << infos.uniform.size()); // UF_DEBUG_MSG("\tAVAILABLE STORAGE BUFFERS: " << infos.storage.size()); @@ -475,10 +510,53 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip // if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ) UF_DEBUG_MSG("\t\tCOMBINED_IMAGE_SAMPLER"); // if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ) UF_DEBUG_MSG("\t\tSAMPLED_IMAGE"); // if ( layout.descriptorType == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE ) UF_DEBUG_MSG("\t\tSTORAGE_IMAGE"); - if ( layout.descriptorCount == 1 ) { - VkDescriptorImageInfo i = (*imageInfo); - // UF_DEBUG_MSG(i.imageView << "\t" << i.imageLayout); + // if ( layout.descriptorCount == 1 ) UF_DEBUG_MSG(i.imageView << "\t" << (*imageInfo).imageLayout); + + #if 1 + std::string binding = std::to_string(layout.binding); + std::string imageType = shader.metadata["definitions"]["textures"][binding]["type"].as(); + if ( imageType == "2D" ) { + BREAK_ASSERT( image2DInfo == infos.image2D.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*image2DInfo), + layout.descriptorCount + )); + image2DInfo += layout.descriptorCount; + } else if ( imageType == "Cube" ) { + BREAK_ASSERT( imageCubeInfo == infos.imageCube.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*imageCubeInfo), + layout.descriptorCount + )); + imageCubeInfo += layout.descriptorCount; + } else if ( imageType == "3D" ) { + BREAK_ASSERT( image3DInfo == infos.image3D.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*image3DInfo), + layout.descriptorCount + )); + image3DInfo += layout.descriptorCount; + } else { + BREAK_ASSERT( imageUnknownInfo == infos.imageUnknown.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) + writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( + descriptorSet, + layout.descriptorType, + layout.binding, + &(*imageUnknownInfo), + layout.descriptorCount + )); + imageUnknownInfo += layout.descriptorCount; } + #else BREAK_ASSERT( imageInfo == infos.image.end(), "Filename: " << shader.filename << "\tCount: " << layout.descriptorCount ) writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet( descriptorSet, @@ -488,6 +566,7 @@ void ext::vulkan::Pipeline::update( Graphic& graphic, GraphicDescriptor& descrip layout.descriptorCount )); imageInfo += layout.descriptorCount; + #endif } break; case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: { // UF_DEBUG_MSG("\t["<< layout.binding << "] INSERTING " << layout.descriptorCount << " INPUT_ATTACHMENT"); diff --git a/engine/src/ext/vulkan/rendermodes/deferred.cpp b/engine/src/ext/vulkan/rendermodes/deferred.cpp index 38442675..84fca510 100644 --- a/engine/src/ext/vulkan/rendermodes/deferred.cpp +++ b/engine/src/ext/vulkan/rendermodes/deferred.cpp @@ -121,6 +121,13 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.samples =*/ 1, }); } + attachments.debug = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format =*/ VK_FORMAT_R32G32B32A32_SFLOAT, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + /*.blend =*/ false, + /*.samples =*/ 1, + }); metadata["outputs"].emplace_back(attachments.output); #if 0 attachments.debug = renderTarget.attach(RenderTarget::Attachment::Descriptor{ @@ -141,6 +148,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.inputs =*/ {}, /*.resolve =*/ {}, /*.depth = */ attachments.depth, + /*.layer = */0, /*.autoBuildPipeline =*/ true ); } @@ -148,10 +156,11 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - /*.colors =*/ { attachments.output }, + /*.colors =*/ { attachments.output, attachments.debug }, /*.inputs =*/ { attachments.id, attachments.normals, attachments.uvs, attachments.depth }, /*.resolve =*/ {}, /*.depth = */ attachments.depth, + /*.layer = */0, /*.autoBuildPipeline =*/ false ); } @@ -164,6 +173,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { /*.inputs =*/ {}, /*.resolve =*/ {}, /*.depth = */ attachments.depth, + /*.layer = */0, /*.autoBuildPipeline =*/ true ); } @@ -171,10 +181,11 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { { renderTarget.addPass( /*.*/ VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - /*.colors =*/ { attachments.output }, + /*.colors =*/ { attachments.output, attachments.debug }, /*.inputs =*/ { attachments.id, attachments.normals, attachments.albedo, attachments.depth }, /*.resolve =*/ {}, /*.depth = */ attachments.depth, + /*.layer = */0, /*.autoBuildPipeline =*/ false ); } @@ -213,25 +224,37 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { auto& shader = blitter.material.shaders.back(); auto& sceneMetadataJson = scene.getComponent(); size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(512); - size_t maxTextures = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(512); + size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as(512); + size_t maxTexturesCube = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["cube"].as(128); + size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as(128); size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(16); if ( ext::vulkan::settings::experimental::deferredMode == "vxgi" ) { + /* struct SpecializationConstant { - uint32_t maxTextures = 512; + uint32_t maxTextures2D = 512; + uint32_t maxTexturesCube = 128; uint32_t maxCascades = 16; }; auto& specializationConstants = shader.specializationConstants.get(); - - specializationConstants.maxTextures = maxTextures; + specializationConstants.maxTextures2D = maxTextures2D; + specializationConstants.maxTexturesCube = maxTexturesCube; specializationConstants.maxCascades = maxCascades; - + */ + uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + ext::json::forEach( shader.metadata["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ + std::string name = sc["name"].as(); + if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); + else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube); + else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades); + }); ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ size_t binding = t["binding"].as(); std::string name = t["name"].as(); for ( auto& layout : shader.descriptorSetLayoutBindings ) { if ( layout.binding != binding ) continue; - if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures; + if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; + else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; @@ -239,26 +262,37 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) { } }); } else { + /* struct SpecializationConstant { - uint32_t maxTextures = 256; + uint32_t maxTextures2D = 512; + uint32_t maxTexturesCube = 128; }; auto& specializationConstants = shader.specializationConstants.get(); - - specializationConstants.maxTextures = maxTextures; + specializationConstants.maxTextures2D = maxTextures2D; + specializationConstants.maxTexturesCube = maxTexturesCube; + */ + uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + ext::json::forEach( shader.metadata["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ + std::string name = sc["name"].as(); + if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); + else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube); + }); ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ - if ( t["name"].as() != "samplerTextures" ) return; size_t binding = t["binding"].as(); + std::string name = t["name"].as(); for ( auto& layout : shader.descriptorSetLayoutBindings ) { - if ( layout.binding == binding ) layout.descriptorCount = maxTextures; + if ( layout.binding != binding ) continue; + if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; + else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; } }); } std::vector lights(maxLights); - std::vector materials(maxTextures); - std::vector textures(maxTextures); - std::vector drawCalls(maxTextures); + std::vector materials(maxTextures2D); + std::vector textures(maxTextures2D); + std::vector drawCalls(maxTextures2D); for ( auto& material : materials ) material.colorBase = {0,0,0,0}; diff --git a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp index de37f233..73f343b7 100644 --- a/engine/src/ext/vulkan/rendermodes/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendermodes/rendertarget.cpp @@ -62,140 +62,61 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { std::string type = metadata["type"].as(); size_t subpasses = metadata["subpasses"].as(); size_t msaa = metadata["samples"].is() ? ext::vulkan::sampleCount(metadata["samples"].as()) : ext::vulkan::settings::msaa; + metadata["outputs"] = ext::json::array(); if ( subpasses == 0 ) subpasses = 1; renderTarget.device = &device; - for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) { - if ( type == "depth" || type == "vxgi" ) { - struct { - size_t depth; - } attachments; + if ( type == "depth" || type == "vxgi" ) { + renderTarget.views = subpasses; + struct { + size_t depth; + } attachments; - 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, - /*.blend = */ false, - /*.samples = */ 1, - }); + 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, + /*.blend = */ false, + /*.samples = */ 1, + }); + for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) { renderTarget.addPass( VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, {}, {}, {}, attachments.depth, + currentPass, true ); - } else if ( type == "single" ) { - struct { - size_t albedo, depth; - } attachments; + } + } else { + for ( size_t currentPass = 0; currentPass < subpasses; ++currentPass ) { + if ( type == "depth" || type == "vxgi" ) { + struct { + size_t depth; + } attachments; - attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R8G8B8A8_UNORM, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */true, - /*.samples = */msaa, - }); - 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, - /*.blend = */ false, - /*.samples = */ 1, - }); - renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.albedo }, - {}, - {}, - attachments.depth, - true - ); - } else { - #if 0 - struct { - size_t albedo, normals, position, depth; - } attachments; - - attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::color, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ true, - /*.samples = */ 1, - }); - attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::normal, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - /*.blend = */ false, - /*.samples = */ 1, - }); - - if ( !settings::experimental::deferredReconstructPosition ) - attachments.position = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */ ext::vulkan::settings::formats::position, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + 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, /*.blend = */ false, /*.samples = */ 1, }); - - 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, - /*.blend = */ false, - /*.samples = */ 1, - }); - - // First pass: write to target - if ( settings::experimental::deferredReconstructPosition ) { renderTarget.addPass( VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.albedo, attachments.normals }, {}, {}, - attachments.depth + {}, + attachments.depth, + 0, + true ); - } else { - renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.albedo, attachments.normals, attachments.position }, - {}, - {}, - attachments.depth - ); - } - #else - struct { - size_t id, normals, uvs, albedo, depth, output; - } attachments; + } else if ( type == "single" ) { + struct { + size_t albedo, depth; + } attachments; - attachments.id = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16_UINT, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, - /*.samples = */msaa, - }); - attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16_SFLOAT, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, - /*.samples = */msaa, - }); - if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { - attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format = */VK_FORMAT_R16G16_UNORM, - /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - /*.blend = */false, - /*.samples = */msaa, - }); - } else { attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ /*.format = */VK_FORMAT_R8G8B8A8_UNORM, /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, @@ -203,70 +124,183 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { /*.blend = */true, /*.samples = */msaa, }); - } - 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, - /*.blend = */false, - /*.samples = */msaa, - }); - attachments.output = renderTarget.attach(RenderTarget::Attachment::Descriptor{ - /*.format =*/ VK_FORMAT_R8G8B8A8_UNORM, - /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - /*.blend =*/ true, - /*.samples =*/ 1, - }); - if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { - // First pass: fill the G-Buffer - { - renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.id, attachments.normals, attachments.uvs }, - {}, - {}, - attachments.depth, - true - ); - } - // Second pass: write to output - { - renderTarget.addPass( - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - { attachments.output }, - { attachments.id, attachments.normals, attachments.uvs, attachments.depth }, - {}, - attachments.depth, - false - ); - } + 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, + /*.blend = */ false, + /*.samples = */ 1, + }); + renderTarget.addPass( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + { attachments.albedo }, + {}, + {}, + attachments.depth, + 0, + true + ); } else { - // First pass: fill the G-Buffer - { + #if 0 + struct { + size_t albedo, normals, position, depth; + } attachments; + + attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */ ext::vulkan::settings::formats::color, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + /*.blend = */ true, + /*.samples = */ 1, + }); + attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */ ext::vulkan::settings::formats::normal, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + /*.blend = */ false, + /*.samples = */ 1, + }); + + if ( !settings::experimental::deferredReconstructPosition ) + attachments.position = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */ ext::vulkan::settings::formats::position, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + /*.blend = */ false, + /*.samples = */ 1, + }); + + 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, + /*.blend = */ false, + /*.samples = */ 1, + }); + + // First pass: write to target + if ( settings::experimental::deferredReconstructPosition ) { renderTarget.addPass( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - { attachments.id, attachments.normals, attachments.albedo }, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + { attachments.albedo, attachments.normals }, {}, {}, - attachments.depth, - true + attachments.depth + ); + } else { + renderTarget.addPass( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + { attachments.albedo, attachments.normals, attachments.position }, + {}, + {}, + attachments.depth ); } - // Second pass: write to output - { - renderTarget.addPass( - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, - { attachments.output }, - { attachments.id, attachments.normals, attachments.albedo, attachments.depth }, - {}, - attachments.depth, - false - ); + #else + struct { + size_t id, normals, uvs, albedo, depth, output; + } attachments; + + attachments.id = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R16G16_UINT, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + attachments.normals = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R16G16_SFLOAT, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { + attachments.uvs = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R16G16_UNORM, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */false, + /*.samples = */msaa, + }); + } else { + attachments.albedo = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format = */VK_FORMAT_R8G8B8A8_UNORM, + /*.layout = */VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage = */VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + /*.blend = */true, + /*.samples = */msaa, + }); } + 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, + /*.blend = */false, + /*.samples = */msaa, + }); + attachments.output = renderTarget.attach(RenderTarget::Attachment::Descriptor{ + /*.format =*/ VK_FORMAT_R8G8B8A8_UNORM, + /*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + /*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + /*.blend =*/ true, + /*.samples =*/ 1, + }); + if ( false && ext::vulkan::settings::experimental::deferredMode != "" ) { + // First pass: fill the G-Buffer + { + renderTarget.addPass( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + { attachments.id, attachments.normals, attachments.uvs }, + {}, + {}, + attachments.depth, + 0, + true + ); + } + // Second pass: write to output + { + renderTarget.addPass( + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + { attachments.output }, + { attachments.id, attachments.normals, attachments.uvs, attachments.depth }, + {}, + attachments.depth, + 0, + false + ); + } + } else { + // First pass: fill the G-Buffer + { + renderTarget.addPass( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + { attachments.id, attachments.normals, attachments.albedo }, + {}, + {}, + attachments.depth, + 0, + true + ); + } + // Second pass: write to output + { + renderTarget.addPass( + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_ACCESS_INPUT_ATTACHMENT_READ_BIT, + { attachments.output }, + { attachments.id, attachments.normals, attachments.albedo, attachments.depth }, + {}, + attachments.depth, + 0, + false + ); + } + } + // metadata["outputs"][0] = attachments.output; + metadata["outputs"].emplace_back(attachments.output); + #endif } - metadata["outputs"][0] = attachments.output; - #endif } } @@ -347,27 +381,40 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { if ( metadata["type"].as() == "vxgi" ) { auto& scene = uf::scene::getCurrentScene(); - auto& shader = blitter.material.getShader("compute"); - struct SpecializationConstant { - uint32_t maxCascades = 16; - uint32_t maxTextures = 512; - }; - auto& specializationConstants = shader.specializationConstants.get(); - auto& sceneMetadataJson = scene.getComponent(); size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as(512); - size_t maxTextures = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"].as(512); + size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as(512); + size_t maxTexturesCube = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["cube"].as(128); + size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as(1); size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as(16); - specializationConstants.maxTextures = maxTextures; + auto& shader = blitter.material.getShader("compute"); + /* + struct SpecializationConstant { + uint32_t maxTextures2D = 512; + uint32_t maxTexturesCube = 128; + uint32_t maxCascades = 16; + }; + auto& specializationConstants = shader.specializationConstants.get(); + specializationConstants.maxTextures2D = maxTextures2D; + specializationConstants.maxTexturesCube = maxTexturesCube; specializationConstants.maxCascades = maxCascades; + */ + uint32_t* specializationConstants = (uint32_t*) (void*) &shader.specializationConstants; + ext::json::forEach( shader.metadata["specializationConstants"], [&]( size_t i, ext::json::Value& sc ){ + std::string name = sc["name"].as(); + if ( name == "TEXTURES" ) sc["value"] = (specializationConstants[i] = maxTextures2D); + else if ( name == "CUBEMAPS" ) sc["value"] = (specializationConstants[i] = maxTexturesCube); + else if ( name == "CASCADES" ) sc["value"] = (specializationConstants[i] = maxCascades); + }); ext::json::forEach( shader.metadata["definitions"]["textures"], [&]( ext::json::Value& t ){ size_t binding = t["binding"].as(); std::string name = t["name"].as(); for ( auto& layout : shader.descriptorSetLayoutBindings ) { if ( layout.binding != binding ) continue; - if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures; + if ( name == "samplerTextures" ) layout.descriptorCount = maxTextures2D; + else if ( name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube; else if ( name == "voxelId" ) layout.descriptorCount = maxCascades; else if ( name == "voxelUv" ) layout.descriptorCount = maxCascades; else if ( name == "voxelNormal" ) layout.descriptorCount = maxCascades; @@ -376,9 +423,9 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) { }); std::vector lights(maxLights); - std::vector materials(specializationConstants.maxTextures); - std::vector textures(specializationConstants.maxTextures); - std::vector drawCalls(specializationConstants.maxTextures); + std::vector materials(maxTextures2D); + std::vector textures(maxTextures2D); + std::vector drawCalls(maxTextures2D); for ( auto& material : materials ) material.colorBase = {0,0,0,0}; @@ -581,14 +628,16 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const std::vecto VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo)); { std::vector clearValues; - for ( auto& attachment : renderTarget.attachments ) { - VkClearValue clearValue; - if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) { - clearValue.color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; - } else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) { - clearValue.depthStencil = { 0.0f, 0 }; + for ( size_t j = 0; j < renderTarget.views; ++j ) { + for ( auto& attachment : renderTarget.attachments ) { + VkClearValue clearValue; + if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) { + clearValue.color = { { 0.0f, 0.0f, 0.0f, 0.0f } }; + } else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) { + clearValue.depthStencil = { 0.0f, 0 }; + } + clearValues.push_back(clearValue); } - clearValues.push_back(clearValue); } VkRenderPassBeginInfo renderPassBeginInfo = {}; diff --git a/engine/src/ext/vulkan/rendertarget.cpp b/engine/src/ext/vulkan/rendertarget.cpp index 35f12207..b86efa19 100644 --- a/engine/src/ext/vulkan/rendertarget.cpp +++ b/engine/src/ext/vulkan/rendertarget.cpp @@ -5,15 +5,15 @@ #include #include -void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFlags access, const std::vector& colors, const std::vector& inputs, const std::vector& resolves, size_t depth, bool autoBuildPipeline ) { +void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFlags access, const std::vector& colors, const std::vector& inputs, const std::vector& resolves, size_t depth, size_t layer, bool autoBuildPipeline ) { Subpass pass; pass.stage = stage; pass.access = access; + pass.layer = layer; pass.autoBuildPipeline = autoBuildPipeline; for ( auto& i : colors ) pass.colors.push_back( { (uint32_t) i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } ); for ( auto& i : inputs ) pass.inputs.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); for ( auto& i : resolves ) pass.resolves.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); -// for ( auto& i : inputs ) pass.inputs.push_back( { (uint32_t) i, i == depth ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL } ); if ( depth < attachments.size() ) pass.depth = { (uint32_t) depth, attachments[depth].descriptor.layout }; if ( !resolves.empty() && resolves.size() != colors.size() ) @@ -22,14 +22,21 @@ void ext::vulkan::RenderTarget::addPass( VkPipelineStageFlags stage, VkAccessFla passes.push_back(pass); } size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descriptor, Attachment* attachment ) { + if ( this->views == 0 ) this->views = 1; + + size_t index = attachments.size(); uint32_t width = this->width > 0 ? this->width : ext::vulkan::settings::width; uint32_t height = this->height > 0 ? this->height : ext::vulkan::settings::height; if ( attachment ) { if ( attachment->view ) { - vkDestroyImageView(*device, attachment->view, nullptr); - attachment->view = VK_NULL_HANDLE; + if ( attachment->view != attachment->views.front() ) { + vkDestroyImageView(*device, attachment->view, nullptr); + attachment->view = VK_NULL_HANDLE; + } } + for ( size_t i = 0; i < this->views; ++i ) vkDestroyImageView(*device, attachment->views[i], nullptr); + attachment->views.clear(); if ( attachment->image ) { vmaDestroyImage( allocator, attachment->image, attachment->allocation ); attachment->image = VK_NULL_HANDLE; @@ -40,6 +47,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript } else { attachment = &attachments.emplace_back(); attachment->descriptor = descriptor; + attachment->views.resize(this->views); } // un-request transient attachments if not supported yet requested if ( attachment->descriptor.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT ) { @@ -71,6 +79,9 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = attachment->descriptor.usage; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + if ( this->views == 6 ) { + imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + } VmaAllocationCreateInfo allocInfo = {}; allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; @@ -89,7 +100,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript } VkImageViewCreateInfo imageView = {}; imageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageView.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageView.viewType = this->views == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D; imageView.format = attachment->descriptor.format; imageView.subresourceRange = {}; imageView.subresourceRange.aspectMask = aspectMask; @@ -98,9 +109,19 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript imageView.subresourceRange.baseArrayLayer = 0; imageView.subresourceRange.layerCount = this->views; imageView.image = attachment->image; - VK_CHECK_RESULT(vkCreateImageView(*device, &imageView, nullptr, &attachment->view)); + if ( this->views == 1 ) { + attachment->views[0] = attachment->view; + } else { + imageView.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageView.subresourceRange.layerCount = 1; + for ( size_t i = 0; i < this->views; ++i ) { + imageView.subresourceRange.baseArrayLayer = i; + VK_CHECK_RESULT(vkCreateImageView(*device, &imageView, nullptr, &attachment->views[i])); + } + } + { VkBool32 blendEnabled = VK_FALSE; VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT; @@ -125,7 +146,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript attachment->blendState = blendAttachmentState; } - return attachments.size()-1; + return index; } void ext::vulkan::RenderTarget::initialize( Device& device ) { // Bind @@ -146,24 +167,35 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { // Create render pass if ( !renderPass ) { std::vector attachments; attachments.reserve( this->attachments.size() ); - - for ( auto& attachment : this->attachments ) { - VkAttachmentDescription description; - description.format = attachment.descriptor.format; - description.samples = ext::vulkan::sampleCount( attachment.descriptor.samples ); - description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - description.storeOp = attachment.descriptor.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; - description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - description.finalLayout = attachment.descriptor.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : attachment.descriptor.layout; - description.flags = 0; + for ( size_t i = 0; i < this->views; ++i ) { + for ( auto& attachment : this->attachments ) { + VkAttachmentDescription description; + description.format = attachment.descriptor.format; + description.samples = ext::vulkan::sampleCount( attachment.descriptor.samples ); + description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + description.storeOp = attachment.descriptor.usage & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE; + description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + description.finalLayout = attachment.descriptor.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : attachment.descriptor.layout; + description.flags = 0; - attachments.push_back(description); + attachments.push_back(description); + } } + // ensure that the subpasses are already described + auto passes = this->passes; assert( passes.size() > 0 ); + + // expand attachment indices + for ( auto& pass : passes ) { + for ( auto& input : pass.inputs ) input.attachment += pass.layer * this->attachments.size(); + for ( auto& color : pass.colors ) color.attachment += pass.layer * this->attachments.size(); + for ( auto& resolve : pass.resolves ) resolve.attachment += pass.layer * this->attachments.size(); + pass.depth.attachment += pass.layer * this->attachments.size(); + } std::vector descriptions; std::vector dependencies; @@ -297,7 +329,6 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { // std::cout << renderPass << ": " << attachments.size() << std::endl; } - { // destroy previous framebuffers for ( auto& framebuffer : framebuffers ) vkDestroyFramebuffer( device, framebuffer, nullptr ); @@ -305,19 +336,21 @@ void ext::vulkan::RenderTarget::initialize( Device& device ) { RenderMode& base = ext::vulkan::getRenderMode( "Swapchain", false ); framebuffers.resize(ext::vulkan::swapchain.buffers); for ( size_t i = 0; i < framebuffers.size(); ++i ) { - std::vector attachments; - for ( auto& attachment : this->attachments ) { - if ( attachment.descriptor.aliased && attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) { - attachments.push_back(base.renderTarget.attachments[i].view); - } else attachments.push_back(attachment.view); + std::vector attachmentViews; + for ( size_t j = 0; j < this->views; ++j ) { + for ( auto& attachment : this->attachments ) { + if ( attachment.descriptor.aliased && attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) { + attachmentViews.push_back(base.renderTarget.attachments[i].view); + } else attachmentViews.push_back(attachment.views[j]); + } } VkFramebufferCreateInfo frameBufferCreateInfo = {}; frameBufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; // All frame buffers use the same renderpass setup frameBufferCreateInfo.renderPass = renderPass; - frameBufferCreateInfo.attachmentCount = static_cast(attachments.size()); - frameBufferCreateInfo.pAttachments = attachments.data(); + frameBufferCreateInfo.attachmentCount = static_cast(attachmentViews.size()); + frameBufferCreateInfo.pAttachments = attachmentViews.data(); frameBufferCreateInfo.width = width; frameBufferCreateInfo.height = height; frameBufferCreateInfo.layers = 1; @@ -335,8 +368,14 @@ void ext::vulkan::RenderTarget::destroy() { for ( auto& attachment : attachments ) { if ( attachment.descriptor.aliased ) continue; - vkDestroyImageView( *device, attachment.view, nullptr ); - attachment.view = VK_NULL_HANDLE; + if ( attachment.view ) { + if ( attachment.view != attachment.views.front() ) { + vkDestroyImageView(*device, attachment.view, nullptr); + attachment.view = VK_NULL_HANDLE; + } + } + for ( size_t i = 0; i < this->views; ++i ) vkDestroyImageView(*device, attachment.views[i], nullptr); + attachment.views.clear(); // vkDestroyImage( *device, attachment.image, nullptr ); vmaDestroyImage( allocator, attachment.image, attachment.allocation ); attachment.image = VK_NULL_HANDLE; diff --git a/engine/src/ext/vulkan/shader.cpp b/engine/src/ext/vulkan/shader.cpp index 7297ea2b..71d7739d 100644 --- a/engine/src/ext/vulkan/shader.cpp +++ b/engine/src/ext/vulkan/shader.cpp @@ -13,7 +13,7 @@ #include #define VK_DEBUG_VALIDATION_MESSAGE(x)\ - //VK_VALIDATION_MESSAGE(x); +// VK_VALIDATION_MESSAGE(x); ext::json::Value ext::vulkan::definitionToJson(/*const*/ ext::json::Value& definition ) { ext::json::Value member; @@ -628,7 +628,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st memcpy( &s[offset], &buffer, size ); offset += size; } - /* + { specializationInfo = {}; specializationInfo.dataSize = specializationSize; @@ -637,7 +637,6 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st specializationInfo.pData = (void*) specializationConstants; descriptor.pSpecializationInfo = &specializationInfo; } - */ } /* */ diff --git a/engine/src/ext/vulkan/texture.cpp b/engine/src/ext/vulkan/texture.cpp index 1553718c..68fffb7d 100644 --- a/engine/src/ext/vulkan/texture.cpp +++ b/engine/src/ext/vulkan/texture.cpp @@ -558,6 +558,8 @@ void ext::vulkan::Texture::asRenderTarget( Device& device, uint32_t width, uint3 void ext::vulkan::Texture::aliasTexture( const Texture& texture ) { image = texture.image; view = texture.view; + type = texture.type; + viewType = texture.viewType; imageLayout = texture.imageLayout; deviceMemory = texture.deviceMemory; width = texture.width; @@ -572,6 +574,8 @@ void ext::vulkan::Texture::aliasTexture( const Texture& texture ) { } void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& attachment, bool createSampler ) { image = attachment.image; + type = VK_IMAGE_TYPE_2D; + viewType = attachment.views.size() == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D; view = attachment.view; imageLayout = attachment.descriptor.layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : attachment.descriptor.layout; deviceMemory = attachment.mem; @@ -584,6 +588,22 @@ void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& atta this->updateDescriptors(); } +void ext::vulkan::Texture::aliasAttachment( const RenderTarget::Attachment& attachment, size_t layer, bool createSampler ) { + image = attachment.image; + type = VK_IMAGE_TYPE_2D; + viewType = VK_IMAGE_VIEW_TYPE_2D; + view = attachment.views[layer]; + imageLayout = attachment.descriptor.layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL : attachment.descriptor.layout; + deviceMemory = attachment.mem; + + // Create sampler + if ( createSampler ) { + // sampler.initialize( ext::vulkan::device ); + sampler = ext::vulkan::Sampler::retrieve( sampler.descriptor ); + } + + this->updateDescriptors(); +} void ext::vulkan::Texture::update( uf::Image& image, VkImageLayout targetImageLayout, uint32_t layer ) { if ( width != image.getDimensions()[0] || height != image.getDimensions()[1] ) return; diff --git a/ext/behaviors/baking/behavior.cpp b/ext/behaviors/baking/behavior.cpp index 98531900..ed1ddfe4 100644 --- a/ext/behaviors/baking/behavior.cpp +++ b/ext/behaviors/baking/behavior.cpp @@ -226,7 +226,7 @@ void ext::BakingBehavior::tick( uf::Object& self ) { light.color = info.color; light.type = info.type; - light.mapIndex = -1; + light.indexMap = -1; light.depthBias = info.bias; if ( info.shadows && entity->hasComponent() ) { @@ -238,14 +238,14 @@ void ext::BakingBehavior::tick( uf::Object& self ) { graphic.material.textures.emplace_back().aliasAttachment(attachment); - light.mapIndex = textureSlot++; + light.indexMap = textureSlot++; light.view = camera.getView(view); light.projection = camera.getProjection(view); lights.emplace_back(light); ++view; } - light.mapIndex = -1; + light.indexMap = -1; } else { lights.emplace_back(light); } diff --git a/ext/behaviors/light/behavior.cpp b/ext/behaviors/light/behavior.cpp index 9e18386c..692bda15 100644 --- a/ext/behaviors/light/behavior.cpp +++ b/ext/behaviors/light/behavior.cpp @@ -227,13 +227,20 @@ void ext::LightBehavior::tick( uf::Object& self ) { if ( metadata.shadows && std::abs(metadata.type) == 1 ) { auto transform = camera.getTransform(); std::vector> rotations = { - uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ), - uf::quaternion::axisAngle( { 0, 1, 0 }, 1 * 1.57079633 ), - uf::quaternion::axisAngle( { 0, 1, 0 }, 2 * 1.57079633 ), - uf::quaternion::axisAngle( { 0, 1, 0 }, 3 * 1.57079633 ), - - uf::quaternion::axisAngle( { 1, 0, 0 }, 1 * 1.57079633 ), - uf::quaternion::axisAngle( { 1, 0, 0 }, 3 * 1.57079633 ), + uf::quaternion::axisAngle( { 0, 1, 0 }, 1 * 1.57079633 ), // right + uf::quaternion::axisAngle( { 0, 1, 0 }, 3 * 1.57079633 ), // left + uf::quaternion::axisAngle( { 1, 0, 0 }, 3 * 1.57079633 ), // down + uf::quaternion::axisAngle( { 1, 0, 0 }, 1 * 1.57079633 ), // up + uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ), // front + uf::quaternion::axisAngle( { 0, 1, 0 }, 2 * 1.57079633 ), // back + /* + uf::quaternion::axisAngle( { 0, 1, 0 }, 1 * 1.57079633 ), // right + uf::quaternion::axisAngle( { 0, 1, 0 }, -1 * 1.57079633 ), // left + uf::quaternion::axisAngle( { 1, 0, 0 }, -1 * 1.57079633 ), // up + uf::quaternion::axisAngle( { 1, 0, 0 }, 1 * 1.57079633 ), // down + uf::quaternion::axisAngle( { 0, 1, 0 }, 0 * 1.57079633 ), // front + uf::quaternion::axisAngle( { 0, 1, 0 }, 2 * 1.57079633 ), // back + */ }; for ( size_t i = 0; i < rotations.size(); ++i ) { auto transform = camera.getTransform(); diff --git a/ext/behaviors/scene/behavior.cpp b/ext/behaviors/scene/behavior.cpp index ce726e0c..e20e458a 100644 --- a/ext/behaviors/scene/behavior.cpp +++ b/ext/behaviors/scene/behavior.cpp @@ -225,7 +225,12 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadataJson["light"]["fog"]["density"]["scale"] = metadata.fog.density.scale; }; metadata.deserialize = [&](){ - metadata.max.textures = ext::config["engine"]["scenes"]["textures"]["max"].as(); + if ( !metadataJson["light"]["point light eye depth scale"].is() ) + metadataJson["light"]["point light eye depth scale"] = ext::config["engine"]["scenes"]["lights"]["point light eye depth scale"]; + + metadata.max.textures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as(); + metadata.max.texturesCube = ext::config["engine"]["scenes"]["textures"]["max"]["cube"].as(); + metadata.max.textures3D = ext::config["engine"]["scenes"]["textures"]["max"]["3D"].as(); metadata.max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as(); metadata.light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); @@ -238,6 +243,9 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { metadata.light.exposure = metadataJson["light"]["exposure"].as(1.0f); metadata.light.gamma = metadataJson["light"]["gamma"].as(2.2f); + metadata.light.experimentalMode = ext::config["engine"]["scenes"]["experimental mode"].as(0); + metadata.light.vxgiShadowSamples = ext::config["engine"]["scenes"]["vxgi shadow samples"].as(0); + metadata.fog.color = uf::vector::decode( metadataJson["light"]["fog"]["color"], pod::Vector3f{ 1, 1, 1 } ); metadata.fog.stepScale = metadataJson["light"]["fog"]["step scale"].as(); metadata.fog.absorbtion = metadataJson["light"]["fog"]["absorbtion"].as(); @@ -366,7 +374,9 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) { #if UF_ENTITY_METADATA_USE_JSON metadata.deserialize(); #else - if ( !metadata.max.textures ) metadata.max.textures = ext::config["engine"]["scenes"]["textures"]["max"].as(); + if ( !metadata.max.textures2D ) metadata.max.textures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as(); + if ( !metadata.max.texturesCube ) metadata.max.texturesCube = ext::config["engine"]["scenes"]["textures"]["max"]["cube"].as(); + if ( !metadata.max.textures3D ) metadata.max.textures3D = ext::config["engine"]["scenes"]["textures"]["max"]["3D"].as(); if ( !metadata.max.lights ) metadata.max.lights = ext::config["engine"]["scenes"]["lights"]["max"].as(); if ( !metadata.light.enabled ) metadata.light.enabled = ext::config["engine"]["scenes"]["lights"]["enabled"].as() && metadataJson["light"]["should"].as(); @@ -453,7 +463,6 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re for ( ; i < metadata.max.lights; ++i ) GL_ERROR_CHECK(glDisable(GL_LIGHT0+i)); } #elif UF_USE_VULKAN - size_t maxTextures = metadata.max.textures; struct UniformDescriptor { struct Matrices { alignas(16) pod::Matrix4f view[2]; @@ -496,11 +505,12 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re alignas(4) uint32_t msaa; alignas(4) uint32_t shadowSamples; alignas(4) float cascadePower; + + alignas(4) uint32_t indexSkybox; + alignas(4) uint32_t vxgiShadowSamples; + alignas(4) uint32_t padding1; + alignas(4) uint32_t padding2; }; - struct SpecializationConstant { - uint32_t maxTextures = 512; - } specializationConstants; - specializationConstants.maxTextures = maxTextures; struct LightInfo { uf::Entity* entity = NULL; @@ -561,190 +571,226 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const std::string& re } entities = scratch; } + auto& sceneTextures = this->getComponent(); + + std::vector textures2D; + std::vector textures3D; + std::vector texturesCube; + + int32_t updateThreshold = metadata.light.updateThreshold; + + std::vector lights; + lights.reserve( metadata.max.lights ); + + std::vector materials; + materials.reserve(metadata.max.textures2D); + materials.emplace_back().colorBase = {0,0,0,0}; + + std::vector textures; + textures.reserve(metadata.max.textures2D); + + std::vector drawCalls; + drawCalls.reserve(metadata.max.textures2D); + + pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; + pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; + + // add materials + for ( auto* g : graphs ) { + auto& graph = *g; + + drawCalls.emplace_back(pod::DrawCall::Storage{ + materials.size(), + graph.materials.size(), + textures.size(), + graph.textures.size() + }); + + for ( auto& material : graph.materials ) materials.emplace_back( material.storage ); + for ( auto& texture : graph.textures ) textures.emplace_back( texture.storage ); + + for ( auto& texture : graph.textures ) { + if ( !texture.bind ) continue; + textures2D.emplace_back().aliasTexture(texture.texture); + } + } + + // add skyboxes + texturesCube.emplace_back().aliasTexture(sceneTextures.skybox); + textures3D.emplace_back().aliasTexture(sceneTextures.noise); + // add lighting + for ( size_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) { + auto& info = entities[i]; + uf::Entity* entity = info.entity; + + auto& transform = entity->getComponent>(); + auto& lightMetadata = entity->getComponent(); + auto& lightCamera = entity->getComponent(); + lightMetadata.renderer.rendered = true; + + pod::Light::Storage light; + light.position = info.position; + + light.color = info.color; + light.type = info.type; + light.typeMap = 0; + light.indexMap = -1; + + light.depthBias = info.bias; + if ( info.shadows && entity->hasComponent() ) { + auto& renderMode = entity->getComponent(); + if ( lightMetadata.renderer.mode == "in-range" && --updateThreshold > 0 ) { + renderMode.execute = true; + // UF_DEBUG_MSG( renderModeName << "\t" << entity->getName() << "\t" << renderMode.execute ); + } + // cubemap + if ( metadata.light.experimentalMode > 0 && renderMode.renderTarget.views == 6 ) { + light.typeMap = metadata.light.experimentalMode; + light.view = lightCamera.getView(0); + light.projection = lightCamera.getProjection(0); + + if ( light.typeMap == 2 ) { + light.indexMap = textures2D.size(); + for ( auto& attachment : renderMode.renderTarget.attachments ) { + if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; + for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { + textures2D.emplace_back().aliasAttachment(attachment, view); + } + break; + } + } else { + light.indexMap = texturesCube.size(); + for ( auto& attachment : renderMode.renderTarget.attachments ) { + if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; + texturesCube.emplace_back().aliasAttachment(attachment); + break; + } + } + + lights.emplace_back(light); + } else { + for ( auto& attachment : renderMode.renderTarget.attachments ) { + if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; + if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue; + for ( size_t view = 0; view < renderMode.renderTarget.views; ++view ) { + + light.indexMap = textures2D.size(); + light.view = lightCamera.getView(view); + light.projection = lightCamera.getProjection(view); + lights.emplace_back(light); + + textures2D.emplace_back().aliasAttachment(attachment, view); + } + } + } + light.indexMap = -1; + } else { + lights.emplace_back(light); + } + } + + // add VXGI + if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { + for ( auto& t : sceneTextures.voxels.id ) textures3D.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.uv ) textures3D.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.normal ) textures3D.emplace_back().aliasTexture(t); + for ( auto& t : sceneTextures.voxels.radiance ) textures3D.emplace_back().aliasTexture(t); + } + +// UF_DEBUG_MSG( "Before: " << textures2D.size() << " | " << metadata.max.textures2D << " || " << texturesCube.size() << " | " << metadata.max.texturesCube << " || " << textures3D.size() << " | " << metadata.max.textures3D ); + while ( textures2D.size() < metadata.max.textures2D ) textures2D.emplace_back().aliasTexture(uf::renderer::Texture2D::empty); + while ( texturesCube.size() < metadata.max.texturesCube ) texturesCube.emplace_back().aliasTexture(uf::renderer::TextureCube::empty); + while ( textures3D.size() < metadata.max.textures3D ) textures3D.emplace_back().aliasTexture(uf::renderer::Texture3D::empty); +// UF_DEBUG_MSG( "After: " << textures2D.size() << " | " << metadata.max.textures2D << " || " << texturesCube.size() << " | " << metadata.max.texturesCube << " || " << textures3D.size() << " | " << metadata.max.textures3D ); + + UniformDescriptor uniforms; { + for ( std::size_t i = 0; i < 2; ++i ) { + uniforms.matrices.view[i] = camera.getView( i ); + uniforms.matrices.projection[i] = camera.getProjection( i ); + uniforms.matrices.iView[i] = uf::matrix::inverse( uniforms.matrices.view[i] ); + uniforms.matrices.iProjection[i] = uf::matrix::inverse( uniforms.matrices.projection[i] ); + uniforms.matrices.iProjectionView[i] = uf::matrix::inverse( uniforms.matrices.projection[i] * uniforms.matrices.view[i] ); + + uniforms.matrices.eyePos[i] = camera.getEye( i ); + } + + uniforms.ambient = metadata.light.ambient; + uniforms.msaa = ext::vulkan::settings::msaa; + uniforms.shadowSamples = shadowSamples; + uniforms.exposure = metadata.light.exposure; + uniforms.gamma = metadata.light.gamma; + + uniforms.indexSkybox = 0; + uniforms.vxgiShadowSamples = metadata.light.vxgiShadowSamples; + + uniforms.fog.color = metadata.fog.color; + uniforms.fog.color.w = metadata.fog.stepScale; + float timescale = metadata.fog.density.timescale; + uniforms.fog.offset = metadata.fog.density.offset * uf::physics::time::current * timescale; + uniforms.fog.offset.w = metadata.fog.density.scale; + uniforms.fog.densityThreshold = metadata.fog.density.threshold; + uniforms.fog.densityMultiplier = metadata.fog.density.multiplier; + uniforms.fog.absorbtion = metadata.fog.absorbtion; + uniforms.fog.range = metadata.fog.range; + + uniforms.mode.type.x = metadataJson["system"]["renderer"]["shader"]["mode"].as(); + uniforms.mode.type.y = metadataJson["system"]["renderer"]["shader"]["scalar"].as(); + uniforms.mode.parameters = uf::vector::decode( metadataJson["system"]["renderer"]["shader"]["parameters"], uniforms.mode.parameters ); + if ( metadataJson["system"]["renderer"]["shader"]["parameters"][3].as() == "time" ) { + uniforms.mode.parameters.w = uf::physics::time::current; + } + + uniforms.matrices.vxgi = sceneTextures.voxels.matrix; + uniforms.cascadePower = sceneTextures.voxels.cascadePower; + + uniforms.lengths.materials = std::min( materials.size(), metadata.max.textures2D ); + uniforms.lengths.textures = std::min( textures.size(), metadata.max.textures2D ); + uniforms.lengths.drawCalls = std::min( drawCalls.size(), metadata.max.textures2D ); + uniforms.lengths.lights = std::min( lights.size(), metadata.max.lights ); + } + for ( auto* blitter : blitters ) { auto& graphic = *blitter; if ( !graphic.initialized ) continue; auto& shader = graphic.material.getShader(isCompute ? "compute" : "fragment"); - auto& uniform = shader.getUniform("UBO"); - uint8_t* buffer = (uint8_t*) (void*) uniform; - - UniformDescriptor* uniforms = (UniformDescriptor*) buffer; - - for ( std::size_t i = 0; i < 2; ++i ) { - uniforms->matrices.view[i] = camera.getView( i ); - uniforms->matrices.projection[i] = camera.getProjection( i ); - uniforms->matrices.iView[i] = uf::matrix::inverse( uniforms->matrices.view[i] ); - uniforms->matrices.iProjection[i] = uf::matrix::inverse( uniforms->matrices.projection[i] ); - uniforms->matrices.iProjectionView[i] = uf::matrix::inverse( uniforms->matrices.projection[i] * uniforms->matrices.view[i] ); - - uniforms->matrices.eyePos[i] = camera.getEye( i ); - } - - uniforms->ambient = metadata.light.ambient; - uniforms->msaa = ext::vulkan::settings::msaa; - uniforms->shadowSamples = shadowSamples; - uniforms->exposure = metadata.light.exposure; - uniforms->gamma = metadata.light.gamma; - - uniforms->fog.color = metadata.fog.color; - uniforms->fog.color.w = metadata.fog.stepScale; - - float timescale = metadata.fog.density.timescale; - uniforms->fog.offset = metadata.fog.density.offset * uf::physics::time::current * timescale; - uniforms->fog.offset.w = metadata.fog.density.scale; - - uniforms->fog.densityThreshold = metadata.fog.density.threshold; - uniforms->fog.densityMultiplier = metadata.fog.density.multiplier; - uniforms->fog.absorbtion = metadata.fog.absorbtion; - - uniforms->fog.range = metadata.fog.range; - - uniforms->mode.type.x = metadataJson["system"]["renderer"]["shader"]["mode"].as(); - uniforms->mode.type.y = metadataJson["system"]["renderer"]["shader"]["scalar"].as(); - uniforms->mode.parameters = uf::vector::decode( metadataJson["system"]["renderer"]["shader"]["parameters"], uniforms->mode.parameters ); - if ( metadataJson["system"]["renderer"]["shader"]["parameters"][3].as() == "time" ) { - uniforms->mode.parameters.w = uf::physics::time::current; - } - + std::vector previousTextures; for ( auto& texture : graphic.material.textures ) previousTextures.emplace_back(texture.image); - graphic.material.textures.clear(); - if ( uf::renderer::settings::experimental::deferredMode == "vxgi" ) { - for ( auto& t : sceneTextures.voxels.id ) { - graphic.material.textures.emplace_back().aliasTexture(t); - } - for ( auto& t : sceneTextures.voxels.uv ) { - graphic.material.textures.emplace_back().aliasTexture(t); - } - for ( auto& t : sceneTextures.voxels.normal ) { - graphic.material.textures.emplace_back().aliasTexture(t); - } - for ( auto& t : sceneTextures.voxels.radiance ) { - graphic.material.textures.emplace_back().aliasTexture(t); - } + + // attach our textures + for ( auto& t : textures2D ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : texturesCube ) graphic.material.textures.emplace_back().aliasTexture(t); + for ( auto& t : textures3D ) graphic.material.textures.emplace_back().aliasTexture(t); + + bool shouldUpdate = graphic.material.textures.size() != previousTextures.size(); + for ( size_t i = 0; !shouldUpdate && i < previousTextures.size() && i < graphic.material.textures.size(); ++i ) { + if ( previousTextures[i] != graphic.material.textures[i].image ) + shouldUpdate = true; } - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.noise); - graphic.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); - - int32_t updateThreshold = metadata.light.updateThreshold; - size_t textureSlot = 0; - - std::vector lights; - lights.reserve( metadata.max.lights ); - - std::vector materials; - materials.reserve(maxTextures); - materials.emplace_back().colorBase = {0,0,0,0}; - - std::vector textures; - textures.reserve(maxTextures); + size_t lightBufferIndex = renderMode.metadata["lightBufferIndex"].as(); + graphic.updateBuffer( (void*) lights.data(), uniforms.lengths.lights * sizeof(pod::Light::Storage), lightBufferIndex, false ); - std::vector drawCalls; - drawCalls.reserve(maxTextures); + if ( shouldUpdate ) { + size_t materialBufferIndex = renderMode.metadata["materialBufferIndex"].as(); + graphic.updateBuffer( (void*) materials.data(), uniforms.lengths.materials * sizeof(pod::Material::Storage), materialBufferIndex, false ); - pod::Vector3f min = { std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max() }; - pod::Vector3f max = { -std::numeric_limits::max(), -std::numeric_limits::max(), -std::numeric_limits::max() }; - - // add materials - for ( auto* g : graphs ) { - auto& graph = *g; - - drawCalls.emplace_back(pod::DrawCall::Storage{ - materials.size(), - graph.materials.size(), - textures.size(), - graph.textures.size() - }); + size_t textureBufferIndex = renderMode.metadata["textureBufferIndex"].as(); + graphic.updateBuffer( (void*) textures.data(), uniforms.lengths.textures * sizeof(pod::Texture::Storage), textureBufferIndex, false ); - for ( auto& material : graph.materials ) materials.emplace_back( material.storage ); - for ( auto& texture : graph.textures ) textures.emplace_back( texture.storage ); + size_t drawCallBufferIndex = renderMode.metadata["drawCallBufferIndex"].as(); + graphic.updateBuffer( (void*) drawCalls.data(), uniforms.lengths.drawCalls * sizeof(pod::DrawCall::Storage), drawCallBufferIndex, false ); - for ( auto& texture : graph.textures ) { - if ( !texture.bind ) continue; - graphic.material.textures.emplace_back().aliasTexture(texture.texture); - ++textureSlot; - } + graphic.updatePipelines(); } - uniforms->matrices.vxgi = sceneTextures.voxels.matrix; - uniforms->cascadePower = sceneTextures.voxels.cascadePower; + + auto& uniform = shader.getUniform("UBO"); + memcpy( (void*) uniform, &uniforms, sizeof(uniforms) ); - uniforms->lengths.materials = std::min( materials.size(), maxTextures ); - uniforms->lengths.textures = std::min( textures.size(), maxTextures ); - uniforms->lengths.drawCalls = std::min( drawCalls.size(), maxTextures ); - // add lighting - for ( size_t i = 0; i < entities.size() && lights.size() < metadata.max.lights; ++i ) { - auto& info = entities[i]; - uf::Entity* entity = info.entity; - - auto& transform = entity->getComponent>(); - auto& metadata = entity->getComponent(); - auto& camera = entity->getComponent(); - metadata.renderer.rendered = true; - - pod::Light::Storage light; - light.position = info.position; - - light.color = info.color; - light.type = info.type; - light.mapIndex = -1; - - light.depthBias = info.bias; - if ( info.shadows && entity->hasComponent() ) { - auto& renderMode = entity->getComponent(); - if ( metadata.renderer.mode == "in-range" && --updateThreshold > 0 ) { - renderMode.execute = true; - // UF_DEBUG_MSG( renderModeName << "\t" << entity->getName() << "\t" << renderMode.execute ); - } - size_t view = 0; - for ( auto& attachment : renderMode.renderTarget.attachments ) { - if ( !(attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue; - if ( attachment.descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ) continue; - - graphic.material.textures.emplace_back().aliasAttachment(attachment); - - light.mapIndex = textureSlot++; - light.view = camera.getView(view); - light.projection = camera.getProjection(view); - lights.emplace_back(light); - - ++view; - } - light.mapIndex = -1; - } else { - lights.emplace_back(light); - } - } - - { - uniforms->lengths.lights = std::min( lights.size(), metadata.max.lights ); - bool shouldUpdate = graphic.material.textures.size() != previousTextures.size(); - for ( size_t i = 0; !shouldUpdate && i < previousTextures.size() && i < graphic.material.textures.size(); ++i ) { - if ( previousTextures[i] != graphic.material.textures[i].image ) - shouldUpdate = true; - } - - size_t lightBufferIndex = renderMode.metadata["lightBufferIndex"].as(); - graphic.updateBuffer( (void*) lights.data(), uniforms->lengths.lights * sizeof(pod::Light::Storage), lightBufferIndex, false ); - - if ( shouldUpdate ) { - size_t materialBufferIndex = renderMode.metadata["materialBufferIndex"].as(); - graphic.updateBuffer( (void*) materials.data(), uniforms->lengths.materials * sizeof(pod::Material::Storage), materialBufferIndex, false ); - - size_t textureBufferIndex = renderMode.metadata["textureBufferIndex"].as(); - graphic.updateBuffer( (void*) textures.data(), uniforms->lengths.textures * sizeof(pod::Texture::Storage), textureBufferIndex, false ); - - size_t drawCallBufferIndex = renderMode.metadata["drawCallBufferIndex"].as(); - graphic.updateBuffer( (void*) drawCalls.data(), uniforms->lengths.drawCalls * sizeof(pod::DrawCall::Storage), drawCallBufferIndex, false ); - - graphic.updatePipelines(); - } - - shader.updateUniform( "UBO", uniform ); - } + shader.updateUniform( "UBO", uniform ); } #endif } diff --git a/ext/behaviors/scene/behavior.h b/ext/behaviors/scene/behavior.h index 483629e4..f4b68fcf 100644 --- a/ext/behaviors/scene/behavior.h +++ b/ext/behaviors/scene/behavior.h @@ -17,7 +17,9 @@ namespace ext { struct Metadata { struct { - size_t textures = 256; + size_t textures2D = 512; + size_t texturesCube = 128; + size_t textures3D = 128; size_t lights = 256; } max; struct { @@ -29,6 +31,9 @@ namespace ext { pod::Vector4f specular = {1,1,1,1}; float exposure = 1.0f; float gamma = 1.0f; + + size_t experimentalMode = 0; + size_t vxgiShadowSamples = 0; } light; struct { pod::Vector3f color = {1,1,1}; diff --git a/ext/behaviors/voxelizer/behavior.cpp b/ext/behaviors/voxelizer/behavior.cpp index 8b57f40d..4e90283e 100644 --- a/ext/behaviors/voxelizer/behavior.cpp +++ b/ext/behaviors/voxelizer/behavior.cpp @@ -89,14 +89,19 @@ void ext::VoxelizerBehavior::initialize( uf::Object& self ) { renderMode.blitter.descriptor.subpass = -1; renderMode.blitter.process = true; + size_t maxTextures2D = ext::config["engine"]["scenes"]["textures"]["max"]["2D"].as(512); + size_t maxTexturesCube = ext::config["engine"]["scenes"]["textures"]["max"]["cube"].as(128); + size_t maxTextures3D = ext::config["engine"]["scenes"]["textures"]["max"]["3D"].as(1); + + for ( size_t i = 0; i < maxTextures2D; ++i ) renderMode.blitter.material.textures.emplace_back().aliasTexture(uf::renderer::Texture2D::empty); + for ( size_t i = 0; i < maxTexturesCube; ++i ) renderMode.blitter.material.textures.emplace_back().aliasTexture(uf::renderer::TextureCube::empty); + for ( size_t i = 0; i < maxTextures3D; ++i ) renderMode.blitter.material.textures.emplace_back().aliasTexture(uf::renderer::Texture3D::empty); + for ( auto& t : sceneTextures.voxels.id ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.uv ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.normal ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); for ( auto& t : sceneTextures.voxels.radiance ) renderMode.blitter.material.textures.emplace_back().aliasTexture(t); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.noise); - renderMode.blitter.material.textures.emplace_back().aliasTexture(sceneTextures.skybox); - renderMode.bindCallback( renderMode.CALLBACK_BEGIN, [&]( VkCommandBuffer commandBuffer ){ // clear textures VkImageSubresourceRange subresourceRange = {}; diff --git a/ext/main.cpp b/ext/main.cpp index 3193e0d5..71480d04 100644 --- a/ext/main.cpp +++ b/ext/main.cpp @@ -774,6 +774,11 @@ void EXT_API ext::terminate() { /* OpenVR */ if ( ext::openvr::context ) { ext::openvr::terminate(); } +#endif +#if UF_USE_LUA + { + ext::lua::terminate(); + } #endif uf::scene::destroy();