Commit for 2022.08.04 23-27-32.7z

This commit is contained in:
mrq 2022-08-04 23:27:00 -05:00
parent cfdb877ed3
commit 96ca870586
49 changed files with 1038 additions and 1103 deletions

View File

@ -100,20 +100,20 @@
},
"gpu": 1,
"experimental": {
"batch queue submissions": false,
"rebuild on tick begin": false,
"dedicated thread": false
"batch queue submissions": true,
"dedicated thread": true
},
"invariant": {},
"pipelines": {
"deferred": true,
"vsync": false,
"hdr": false,
"vsync": true,
"hdr": true,
"vxgi": true,
"culling": true,
"culling": false,
"bloom": true,
"rt": true,
"postProcess": false,
"postProcess": true,
"fsr": true
},
"formats": {
@ -221,7 +221,7 @@
"fsr": {
"enabled": true,
"sharpness": 1,
"jitter scale": 0.0125,
"jitter scale": 0.0625,
"preset": "ultra" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x)
},
"reactphysics": {

View File

@ -46,9 +46,9 @@
"output": "./lightmap.%i.png",
"settings": {
"useInputMeshUvs": true,
"maxIterations": 1,
"maxIterations": 4,
// "maxChartSize": 0,
"padding": 4,
"padding": 2,
// "texelsPerUnit": 0,
"bilinear": true,
"blockAlign": true,

View File

@ -49,21 +49,6 @@
"sigma": 1.0,
"samples": 4
},
"fog": {
// "color": [ 0.1, 0.1, 0.1 ],
// "color": [ 0.2, 0.2, 0.2 ],
"color": [ 0.3, 0.3, 0.3 ],
"range": [ 64, 256 ],
"step scale": 4,
"absorbtion": 0.0125,
"density": {
"threshold": 0.35,
"multiplier": 2.0,
"scale": 25.0,
"offset": [0.2, 0, 1],
"timescale": 32
}
},
"shadows": {
"enabled": true
}

View File

@ -13,7 +13,7 @@
// exact matches
// "worldspawn_skybox": { "ignore": true },
"worldspawn_skybox": {
"grid": { "size": [3,1,3], "epsilon": 1.0, "cleanup": true, "print": true },
"grid": { "size": [5,1,5], "epsilon": 1.0, "cleanup": true, "print": true },
"unwrap mesh": true,
"optimize mesh": { "simplify": 0 }
},

View File

@ -13,7 +13,7 @@
// "ambient": [ 0.8, 0.8, 0.8 ],
// "ambient": [ 0.1, 0.1, 0.2 ],
"exposure": 1, // 0.125,
"exposure": 0.125,
"gamma": 2.2, // 2.2,
"bloom": {
@ -22,6 +22,22 @@
"strength": 1,
"sigma": 1.0,
"samples": 4
},
"fog": {
// "color": [ 0.1, 0.1, 0.1 ],
// "color": [ 0.2, 0.2, 0.2 ],
"color": [ 0.3, 0.3, 0.3 ],
"range": [ 64, 256 ],
"step scale": 4,
"absorbtion": 0.0125,
"density": {
"threshold": 0.35,
"multiplier": 2.0,
"scale": 25.0,
"offset": [0.2, 0, 1],
"timescale": 32
}
}
}
}

View File

@ -7,7 +7,7 @@
"metadata": {
"graph": {
"lights": {
"lightmap": false
// "lightmap": false
},
"assets": [
"./audio/soundscape/sh2_ambience.ogg"

View File

@ -1,6 +1,6 @@
{
// "import": "./rp_downtown_v2.json"
"import": "./ss2_medsci1.json"
// "import": "./sh2_mcdonalds.json"
// "import": "./ss2_medsci1.json"
"import": "./sh2_mcdonalds.json"
// "import": "./gm_construct.json"
}

View File

@ -10,6 +10,12 @@ float mipLevel( in vec2 dx_vtc, in vec2 dy_vtc ) {
// return 0.5 * log2(max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)));
}
float mipLevels( vec2 size ) {
return floor(log2(max(size.x, size.y)));
}
float mipLevels( ivec2 size ) {
return floor(log2(max(size.x, size.y)));
}
//
void toneMap( inout vec3 color, float exposure ) {
color.rgb = vec3(1.0) - exp(-color.rgb * exposure);

View File

@ -87,8 +87,8 @@ struct DrawCommand {
int vertexID; // starting vertex position
uint instanceID; // starting instance position
uint auxID; //
uint materialID; // material to use for this draw call
float padding1; //
float padding2; // material to use for this draw call
uint vertices; // number of vertices used
};

View File

@ -15,6 +15,8 @@ layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#define PBR 1
#define BUFFER_REFERENCE 1
#define UINT64_ENABLED 1
#define FOG 1
#define FOG_RAY_MARCH 1
#include "../../../common/macros.h"
@ -222,12 +224,6 @@ void populateSurface() {
}
void directLighting() {
#if RT && COMPUTE && !VXGI
{
}
#endif
surface.light.rgb += surface.material.albedo.rgb * ubo.settings.lighting.ambient.rgb * surface.material.occlusion; // add ambient lighting
surface.light.rgb += surface.material.indirect.rgb; // add indirect lighting
#if PBR

View File

@ -0,0 +1,30 @@
#version 450
#pragma shader_stage(compute)
//#extension GL_EXT_nonuniform_qualifier : enable
layout (constant_id = 0) const uint MIPS = 6;
layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
#define COMPUTE 1
#include "../../common/macros.h"
#include "../../common/structs.h"
layout( push_constant ) uniform PushBlock {
uint _;
uint pass;
} PushConstant;
layout (binding = 3) uniform sampler2D inImage[MIPS];
layout (binding = 4, r32f) uniform volatile coherent image2D outImage[MIPS];
void main() {
vec2 imageSize = imageSize(outImage[PushConstant.pass]);
uvec2 pos = gl_GlobalInvocationID.xy;
if ( pos.x >= imageSize.x || pos.y >= imageSize.y ) return;
float depth = texture(inImage[PushConstant.pass], (vec2(pos) + vec2(0.5)) / imageSize).x;
imageStore(outImage[PushConstant.pass], ivec2(pos), vec4(depth));
}

View File

@ -1,210 +1,5 @@
#version 450
#pragma shader_stage(fragment)
//#extension GL_EXT_nonuniform_qualifier : enable
layout (constant_id = 0) const uint TEXTURES = 512;
layout (constant_id = 1) const uint CUBEMAPS = 128;
layout (constant_id = 2) const uint LAYERS = 32;
layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 6) uniform samplerCube samplerCubemaps[CUBEMAPS];
#define SHADOW_SAMPLES 16
#define FRAGMENT 1
#define BAKING 1
#include "../../common/macros.h"
#include "../../common/structs.h"
layout (binding = 7) uniform Camera {
Viewport viewport[6];
} camera;
layout (binding = 8) uniform UBO {
uint lights;
uint currentID;
uint padding1;
uint padding2;
} ubo;
layout (std140, binding = 9) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
layout (std140, binding = 10) readonly buffer Instances {
Instance instances[];
};
layout (std140, binding = 11) readonly buffer InstanceAddresseses {
InstanceAddresses instanceAddresses[];
};
layout (std140, binding = 12) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 13) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 14) readonly buffer Lights {
Light lights[];
};
layout (binding = 15, rgba8) uniform volatile coherent image3D outAlbedos;
#include "../../common/functions.h"
#include "../../common/shadows.h"
#define PBR 1
layout (location = 0) flat in uvec4 inId;
layout (location = 1) flat in vec4 inPOS0;
layout (location = 2) in vec4 inPOS1;
layout (location = 3) in vec3 inPosition;
layout (location = 4) in vec2 inUv;
layout (location = 5) in vec4 inColor;
layout (location = 6) in vec2 inSt;
layout (location = 7) in vec3 inNormal;
layout (location = 8) in vec3 inTangent;
layout (location = 0) out vec4 outAlbedo;
void main() {
const uint triangleID = uint(inId.x); // gl_PrimitiveID
const uint drawID = uint(inId.y);
const uint instanceID = uint(inId.z);
if ( instanceID != ubo.currentID ) discard;
surface.uv.xy = wrap(inUv.xy);
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
surface.position.world = inPosition;
surface.normal.world = inNormal;
const DrawCommand drawCommand = drawCommands[drawID];
const Instance instance = instances[instanceID];
const Material material = materials[instance.materialID];
const uint mapID = instance.auxID;
vec4 A = material.colorBase;
surface.material.metallic = material.factorMetallic;
surface.material.roughness = material.factorRoughness;
surface.material.occlusion = 1.0f - material.factorOcclusion;
#if 0
vec3 N = inNormal;
vec3 T = inTangent;
T = normalize(T - dot(T, N) * N);
vec3 B = cross(T, N);
mat3 TBN = mat3(T, B, N);
// mat3 TBN = mat3(N, B, T);
if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) {
surface.normal.world = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 );
} else {
surface.normal.world = N;
}
#endif
surface.light = material.colorEmissive;
surface.material.albedo = vec4(1);
#if 1
#if 1
{
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
for ( uint i = 0; i < min(ubo.lights, lights.length()); ++i ) {
const Light light = lights[i];
if ( light.type <= 0 ) continue;
const mat4 mat = light.view; // inverse(light.view);
const vec3 position = surface.position.world;
// const vec3 position = vec3( mat * vec4(surface.position.world, 1.0) );
const vec3 normal = surface.normal.world;
// const vec3 normal = vec3( mat * vec4(surface.normal.world, 0.0) );
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lp = light.position;
const vec3 Liu = light.position - surface.position.world;
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
const float Ls = shadowFactor( light, 0.0 );
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lo = normalize( -position );
const float cosLo = max(0.0, abs(dot(normal, Lo)));
const vec3 Li = normalize(Liu);
const vec3 Lr = light.color.rgb * light.power * La * Ls;
// const float cosLi = max(0.0, dot(normal, Li));
const float cosLi = abs(dot(normal, Li));
#if LAMBERT
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
#elif PBR
const vec3 Lh = normalize(Li + Lo);
// const float cosLh = max(0.0, dot(normal, Lh));
const float cosLh = abs(dot(normal, Lh));
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
const float D = 1; // ndfGGX( cosLh, surface.material.roughness );
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
#else
{
// corrections
surface.material.roughness *= 4.0;
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
const vec3 Lo = normalize( surface.position.world );
const float cosLo = max(0.0, dot(surface.normal.world, Lo));
for ( uint i = 0; i < lights.length(); ++i ) {
const Light light = lights[i];
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
if ( light.type >= 0 && validTextureIndex( surface.instance.lightmapID ) ) continue;
const vec3 Lp = light.position;
const vec3 Liu = light.position - surface.position.world;
const vec3 Li = normalize(Liu);
const float Ls = shadowFactor( light, 0.0 );
const float La = 1.0 / (PI * pow(length(Liu), 2.0));
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
const float cosLi = max(0.0, dot(surface.normal.world, Li));
const vec3 Lr = light.color.rgb * light.power * La * Ls;
#if LAMBERT
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
#elif PBR
const vec3 Lh = normalize(Li + Lo);
const float cosLh = max(0.0, dot(surface.normal.world, Lh));
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
const float D = ndfGGX( cosLh, surface.material.roughness );
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
#endif
#endif
#define EXPOSURE 0
#define GAMMA 0
// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE);
// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA));
outAlbedo = vec4(surface.light.rgb, 1);
{
const vec2 st = inSt.xy * imageSize(outAlbedos).xy;
const ivec3 uvw = ivec3(int(st.x), int(st.y), int(mapID));
imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) );
}
}
#define RT 0
#include "./frag.h"

View File

@ -0,0 +1,196 @@
//#extension GL_EXT_nonuniform_qualifier : enable
#if RT
#extension GL_EXT_ray_tracing : enable
#extension GL_EXT_ray_query : enable
#endif
layout (constant_id = 0) const uint TEXTURES = 512;
layout (constant_id = 1) const uint CUBEMAPS = 128;
layout (constant_id = 2) const uint LAYERS = 32;
layout (binding = 5) uniform sampler2D samplerTextures[TEXTURES];
layout (binding = 6) uniform samplerCube samplerCubemaps[CUBEMAPS];
#define SHADOW_SAMPLES 16
#define FRAGMENT 1
#define BAKING 1
#include "../../common/macros.h"
#include "../../common/structs.h"
layout (binding = 7) uniform Camera {
Viewport viewport[6];
} camera;
layout (binding = 8) uniform UBO {
uint lights;
uint currentID;
uint padding1;
uint padding2;
} ubo;
layout (std140, binding = 9) readonly buffer DrawCommands {
DrawCommand drawCommands[];
};
layout (std140, binding = 10) readonly buffer Instances {
Instance instances[];
};
layout (std140, binding = 11) readonly buffer InstanceAddresseses {
InstanceAddresses instanceAddresses[];
};
layout (std140, binding = 12) readonly buffer Materials {
Material materials[];
};
layout (std140, binding = 13) readonly buffer Textures {
Texture textures[];
};
layout (std140, binding = 14) readonly buffer Lights {
Light lights[];
};
layout (binding = 15, rgba8) uniform volatile coherent image3D outAlbedos;
#if RT
layout (binding = 16) uniform accelerationStructureEXT tlas;
#endif
#include "../../common/functions.h"
#if RT
float shadowFactor( const Light light, float def ) {
Ray ray;
ray.origin = surface.position.world;
ray.direction = light.position - ray.origin;
float tMin = 0.001;
float tMax = length(ray.direction) + tMin;
ray.direction = normalize(ray.direction);
uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsSkipClosestHitShaderEXT;
uint cullMask = 0xFF;
rayQueryEXT rayQuery;
rayQueryInitializeEXT(rayQuery, tlas, rayFlags, cullMask, ray.origin, tMin, ray.direction, tMax);
while(rayQueryProceedEXT(rayQuery)) {}
return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0;
}
#else
#include "../../common/shadows.h"
#endif
#define PBR 1
layout (location = 0) flat in uvec4 inId;
layout (location = 1) flat in vec4 inPOS0;
layout (location = 2) in vec4 inPOS1;
layout (location = 3) in vec3 inPosition;
layout (location = 4) in vec2 inUv;
layout (location = 5) in vec4 inColor;
layout (location = 6) in vec2 inSt;
layout (location = 7) in vec3 inNormal;
layout (location = 8) in vec3 inTangent;
layout (location = 0) out vec4 outAlbedo;
void main() {
const uint triangleID = uint(inId.x); // gl_PrimitiveID
const uint drawID = uint(inId.y);
const uint instanceID = uint(inId.z);
if ( instanceID != ubo.currentID ) discard;
surface.uv.xy = wrap(inUv.xy);
surface.uv.z = mipLevel(dFdx(inUv), dFdy(inUv));
surface.position.world = inPosition;
surface.normal.world = inNormal;
const DrawCommand drawCommand = drawCommands[drawID];
const Instance instance = instances[instanceID];
const Material material = materials[instance.materialID];
const uint mapID = instance.auxID;
vec4 A = material.colorBase;
surface.material.metallic = material.factorMetallic;
surface.material.roughness = material.factorRoughness;
surface.material.occlusion = 1.0f - material.factorOcclusion;
#if 0
vec3 N = inNormal;
vec3 T = inTangent;
T = normalize(T - dot(T, N) * N);
vec3 B = cross(T, N);
mat3 TBN = mat3(T, B, N);
// mat3 TBN = mat3(N, B, T);
if ( T != vec3(0) && validTextureIndex( material.indexNormal ) ) {
surface.normal.world = TBN * normalize( sampleTexture( material.indexNormal ).xyz * 2.0 - 1.0 );
} else {
surface.normal.world = N;
}
#endif
surface.light = material.colorEmissive;
surface.material.albedo = vec4(1);
{
const vec3 F0 = mix(vec3(0.04), surface.material.albedo.rgb, surface.material.metallic);
for ( uint i = 0; i < min(ubo.lights, lights.length()); ++i ) {
const Light light = lights[i];
if ( light.type <= 0 ) continue;
const mat4 mat = light.view; // inverse(light.view);
const vec3 position = surface.position.world;
// const vec3 position = vec3( mat * vec4(surface.position.world, 1.0) );
const vec3 normal = surface.normal.world;
// const vec3 normal = vec3( mat * vec4(surface.normal.world, 0.0) );
if ( light.power <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lp = light.position;
const vec3 Liu = light.position - surface.position.world;
const float La = 1.0 / (1 + PI * pow(length(Liu), 2.0));
const float Ls = shadowFactor( light, 0.0 );
if ( light.power * La * Ls <= LIGHT_POWER_CUTOFF ) continue;
const vec3 Lo = normalize( -position );
const float cosLo = max(0.0, abs(dot(normal, Lo)));
const vec3 Li = normalize(Liu);
const vec3 Lr = light.color.rgb * light.power * La * Ls;
// const float cosLi = max(0.0, dot(normal, Li));
const float cosLi = abs(dot(normal, Li));
#if LAMBERT
const vec3 diffuse = surface.material.albedo.rgb;
const vec3 specular = vec3(0);
#elif PBR
const vec3 Lh = normalize(Li + Lo);
// const float cosLh = max(0.0, dot(normal, Lh));
const float cosLh = abs(dot(normal, Lh));
const vec3 F = fresnelSchlick( F0, max( 0.0, dot(Lh, Lo) ) );
const float D = 1; // ndfGGX( cosLh, surface.material.roughness );
const float G = gaSchlickGGX(cosLi, cosLo, surface.material.roughness);
const vec3 diffuse = mix( vec3(1.0) - F, vec3(0.0), surface.material.metallic ) * surface.material.albedo.rgb;
const vec3 specular = (F * D * G) / max(EPSILON, 4.0 * cosLi * cosLo);
#endif
surface.light.rgb += (diffuse + specular) * Lr * cosLi;
surface.light.a += light.power * La * Ls;
}
}
#define EXPOSURE 0
#define GAMMA 0
// surface.light.rgb = vec3(1.0) - exp(-surface.light.rgb * EXPOSURE);
// surface.light.rgb = pow(surface.light.rgb, vec3(1.0 / GAMMA));
outAlbedo = vec4(surface.light.rgb, 1);
{
const vec2 st = inSt.xy * imageSize(outAlbedos).xy;
const ivec3 uvw = ivec3(int(st.x), int(st.y), int(mapID));
imageStore(outAlbedos, uvw, vec4(surface.light.rgb, 1) );
}
}

View File

@ -0,0 +1,5 @@
#version 460
#pragma shader_stage(fragment)
#define RT 1
#include "./frag.h"

View File

@ -2,15 +2,54 @@
#pragma shader_stage(compute)
//#extension GL_EXT_nonuniform_qualifier : enable
#extension GL_EXT_samplerless_texture_functions : enable
layout (constant_id = 0) const uint PASSES = 6;
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
#define COMPUTE 1
#define QUERY_MIPMAPS 1
#define DEPTH_BIAS 0.00005
#include "../../common/macros.h"
#include "../../common/structs.h"
float mipLevels( vec2 size ) {
return floor(log2(max(size.x, size.y)));
}
float mipLevels( ivec2 size ) {
return floor(log2(max(size.x, size.y)));
}
vec4 aabbToSphere( Bounds bounds ) {
vec4 sphere;
sphere.xyz = (bounds.max + bounds.min) * 0.5;
sphere.w = length((bounds.max - bounds.min) * 0.5);
return sphere;
}
// 2D Polyhedral Bounds of a Clipped, Perspective-Projected 3D Sphere. Michael Mara, Morgan McGuire. 2013
bool projectSphere(vec3 C, float r, float znear, float P00, float P11, out vec4 aabb)
{
if (C.z < r + znear)
return false;
vec2 cx = -C.xz;
vec2 vx = vec2(sqrt(dot(cx, cx) - r * r), r);
vec2 minx = mat2(vx.x, vx.y, -vx.y, vx.x) * cx;
vec2 maxx = mat2(vx.x, -vx.y, vx.y, vx.x) * cx;
vec2 cy = -C.yz;
vec2 vy = vec2(sqrt(dot(cy, cy) - r * r), r);
vec2 miny = mat2(vy.x, vy.y, -vy.y, vy.x) * cy;
vec2 maxy = mat2(vy.x, -vy.y, vy.y, vy.x) * cy;
aabb = vec4(minx.x / minx.y * P00, miny.x / miny.y * P11, maxx.x / maxx.y * P00, maxy.x / maxy.y * P11);
aabb = aabb.xwzy * vec4(0.5f, -0.5f, 0.5f, -0.5f) + vec4(0.5f); // clip space -> uv space
return true;
}
layout( push_constant ) uniform PushBlock {
uint pass;
uint passes;
@ -28,6 +67,8 @@ layout (std140, binding = 2) buffer Instances {
Instance instances[];
};
layout (binding = 3) uniform sampler2D samplerDepth;
struct Frustum {
vec4 planes[6];
};
@ -44,72 +85,12 @@ bool frustumCull( uint id ) {
bool visible = false;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
// return if our camera position is inside the AABB
// vec3 camPos = vec3( inverse(camera.viewport[pass].view)[3] );
// if ( instance.bounds.min.x <= camPos.x && camPos.x <= instance.bounds.max.x && instance.bounds.min.y <= camPos.y && camPos.y <= instance.bounds.max.y && instance.bounds.min.z <= camPos.z && camPos.z <= instance.bounds.max.z ) return true;
// sphere based one, source of this block uses reverse infinite Z, but would be nice if it used AABB
// doesn't work
#if 0
vec3 min = vec3(camera.viewport[pass].view * instance.model * vec4(instance.bounds.min, 1));
vec3 max = vec3(camera.viewport[pass].view * instance.model * vec4(instance.bounds.max, 1));
vec3 center = (max + min) * 0.5;
vec3 extent = (max - min) * 0.5;
float radius = length(extent);
mat4 projectionT = transpose(camera.viewport[pass].projection);
vec4 frustumX = normalizePlane(projectionT[3] + projectionT[0]); // x + w < 0
vec4 frustumY = normalizePlane(projectionT[3] + projectionT[1]); // y + w < 0
vec4 frustum = vec4( frustumX.x, frustumX.z, frustumY.y, frustumY.z );
visible = visible && center.z * frustum[1] - abs(center.x) * frustum[0] > -radius;
visible = visible && center.z * frustum[3] - abs(center.y) * frustum[2] > -radius;
// optimized version of the below blocks
// doesn't work
#elif 0
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec3 min = vec3(mat * vec4(instance.bounds.min, 1));
vec3 max = vec3(mat * vec4(instance.bounds.max, 1));
vec3 center = (max + min) * 0.5;
vec3 extent = (max - min) * 0.5;
vec4 planes[6]; {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
planes[i*2+j] = normalizePlane( planes[i*2+j] );
}
}
for ( uint p = 0; p < 6; ++p ) {
if ( dot(center + extent * sign(planes[p].xyz), planes[p].xyz ) > -planes[p].w ) return true;
}
// transforms each corner into clip space
// an AABB is not visible if a plane has all 8 corners outside of it
// doesn't work
#elif 0
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec4 corners[8] = {
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
};
for ( uint p = 0; p < 8; ++p ) {
vec4 t = mat * corners[p];
if ( -t.w <= t.x && t.x <= t.w && -t.w <= t.y && t.y <= t.w && -t.w <= t.z && t.z <= t.w ) return true;
}
// "optimized" version of the next block, compares bounds to each plane
// an AABB is not visible if a plane has all 8 corners outside of it
#elif 1
#if 0
vec4 sphere = aabbToSphere( instance.bounds );
vec3 center = vec3( camera.viewport[pass].view * instance.model * vec4( ) );
#else
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
#if 1
vec4 planes[6]; {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j) {
@ -127,7 +108,6 @@ bool frustumCull( uint id ) {
if ( d > -planes[p].w ) return true;
}
#else
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec4 corners[8] = {
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
@ -161,6 +141,134 @@ bool frustumCull( uint id ) {
}
return false;
}
#endif
#endif
}
return visible;
}
bool occlusionCull( uint id ) {
if ( PushConstant.passes == 0 ) return true;
const DrawCommand drawCommand = drawCommands[id];
const Instance instance = instances[drawCommand.instanceID];
bool visible = true;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
#if 1
vec4 aabb;
vec4 sphere = aabbToSphere( instance.bounds );
vec3 center = (camera.viewport[pass].view * instance.model * vec4(sphere.xyz, 1)).xyz;
float radius = (instance.model * vec4(sphere.w, 0, 0, 0)).x;
// center.y *= -1;
mat4 proj = camera.viewport[pass].projection;
float znear = proj[3][2];
float P00 = proj[0][0];
float P11 = proj[1][1];
if (projectSphere(center, radius, znear, P00, P11, aabb)) {
ivec2 pyramidSize = textureSize( samplerDepth, 0 );
float mips = mipLevels( pyramidSize );
float width = (aabb.z - aabb.x) * pyramidSize.x;
float height = (aabb.w - aabb.y) * pyramidSize.y;
//find the mipmap level that will match the screen size of the sphere
float level = floor(log2(max(width, height)));
// if ( level == mips )
--level;
level = clamp( level, 0, mips );
//sample the depth pyramid at that specific level
float depth = textureLod(samplerDepth, (aabb.xy + aabb.zw) * 0.5, level).x;
float depthSphere = znear / (center.z - radius);
instances[drawCommand.instanceID].bounds.padding1 = depth;
instances[drawCommand.instanceID].bounds.padding2 = proj[3][2];
//if the depth of the sphere is in front of the depth pyramid value, then the object is visible
visible = visible && depthSphere >= depth - DEPTH_BIAS;
}
#else
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
vec3 boundsSize = instance.bounds.max - instance.bounds.min;
vec3 points[8] = {
instance.bounds.min.xyz,
instance.bounds.min.xyz + vec3(boundsSize.x,0,0),
instance.bounds.min.xyz + vec3(0, boundsSize.y,0),
instance.bounds.min.xyz + vec3(0, 0, boundsSize.z),
instance.bounds.min.xyz + vec3(boundsSize.xy,0),
instance.bounds.min.xyz + vec3(0, boundsSize.yz),
instance.bounds.min.xyz + vec3(boundsSize.x, 0, boundsSize.z),
instance.bounds.min.xyz + boundsSize.xyz,
};
vec2 minXY = vec2(1);
vec2 maxXY = vec2(0);
float minZ = 1;
float maxZ = 0;
#pragma unroll 8
for ( uint i = 0; i < 8; ++i ) {
vec4 clip = mat * vec4( points[i], 1 );
clip.xyz /= clip.w;
clip.xy = clip.xy * 0.5 + 0.5;
minXY.x = min(minXY.x, clip.x);
minXY.y = min(minXY.y, clip.y);
maxXY.x = max(maxXY.x, clip.x);
maxXY.y = max(maxXY.y, clip.y);
#if INVERSE
clip.z = 1.0 - clip.z;
maxZ = max(maxZ, clip.z);
#else
minZ = min(minZ, clip.z);
#endif
}
if ( maxXY.x <= 0 || maxXY.y <= 0 ) return false;
if ( minXY.x >= 1 || minXY.y >= 1 ) return false;
ivec2 depthSize = textureSize( samplerDepth, 0 );
float mips = mipLevels( depthSize );
vec4 uv = vec4(minXY, maxXY);
ivec2 clipSize = ivec2(maxXY - minXY) * depthSize;
float mip = mipLevels( clipSize );
mip = clamp( mip, 0, mips );
if ( mip == 0 ) {
mip = 1;
} else {
float lower = max(mip - 1, 0);
float scale = exp2(-lower);
vec2 a = floor(uv.xy * scale);
vec2 b = ceil(uv.zw * scale);
vec2 dims = b - a;
// Use the lower level if we only touch <= 2 texels in both dimensions
if (dims.x <= 2 && dims.y <= 2) mip = lower;
}
float depths[4] = {
textureLod( samplerDepth, uv.xy, mip ).r,
textureLod( samplerDepth, uv.zy, mip ).r,
textureLod( samplerDepth, uv.xw, mip ).r,
textureLod( samplerDepth, uv.zw, mip ).r,
};
#if INVERSE
float minDepth = 1.0 - min(min(min(depths[0], depths[1]), depths[2]), depths[3]);
#else
float maxDepth = max(max(max(depths[0], depths[1]), depths[2]), depths[3]);
#endif
instances[drawCommand.instanceID].bounds.padding1 = minZ;
instances[drawCommand.instanceID].bounds.padding2 = maxDepth;
return minZ <= maxDepth;
#endif
}
return visible;
@ -169,7 +277,11 @@ bool frustumCull( uint id ) {
void main() {
const uint gID = gl_GlobalInvocationID.x;
if ( !(0 <= gID && gID < drawCommands.length()) ) return;
drawCommands[gID].instances = frustumCull( gID ) ? 1 : 0;
bool visible = frustumCull( gID );
if ( visible ) visible = occlusionCull( gID );
// bool visible = occlusionCull( gID );
drawCommands[gID].instances = visible ? 1 : 0;
}

View File

@ -1,52 +0,0 @@
#version 450
#pragma shader_stage(compute)
//#extension GL_EXT_nonuniform_qualifier : enable
layout (constant_id = 0) const uint PASSES = 6;
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
#define COMPUTE 1
#include "../../common/macros.h"
#include "../../common/structs.h"
layout( push_constant ) uniform PushBlock {
uint pass;
uint passes;
} PushConstant;
layout (binding = 0) uniform Camera {
Viewport viewport[PASSES];
} camera;
layout (std140, binding = 1) buffer DrawCommands {
DrawCommand drawCommands[];
};
layout (std140, binding = 2) buffer Instances {
Instance instances[];
};
layout (binding = 3) uniform sampler2D samplerID;
layout (binding = 4) uniform sampler2D samplerDepth;
bool frustumCull( uint id ) {
if ( PushConstant.passes == 0 ) return true;
const DrawCommand drawCommand = drawCommands[id];
const Instance instance = instances[drawCommand.instanceID];
bool visible = true;
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * instance.model;
}
return visible;
}
void main() {
const uint gID = gl_GlobalInvocationID.x;
if ( !(0 <= gID && gID < drawCommands.length()) ) return;
if ( drawCommands[gID].instances == 0 ) return;
// drawCommands[gID].instances = frustumCull( gID ) ? 1 : 0;
}

View File

@ -168,9 +168,5 @@ void client::render() {
}
void client::terminate() {
/* Close Threads */ {
uf::thread::terminate();
}
client::window.terminate();
}

View File

@ -77,7 +77,8 @@ int main(int argc, char** argv){
try {
#endif
if ( uf::renderer::settings::experimental::dedicatedThread /*&& !uf::renderer::states::rebuild*/ ) {
auto& thread = uf::thread::fetchWorker();
// auto& thread = uf::thread::fetchWorker();
auto& thread = uf::thread::get("Render");
uf::thread::queue(thread, [&]{
ext::render();
client::render();
@ -88,14 +89,11 @@ int main(int argc, char** argv){
uf::thread::wait( thread );
} else {
// UF_TIMER_MULTITRACE_START("Frame Start");
client::tick();
ext::tick();
// UF_TIMER_MULTITRACE("Ticked");
ext::render();
client::render();
// UF_TIMER_MULTITRACE("Rendered");
// UF_TIMER_MULTITRACE_END("Frame End");
}
#if UF_EXCEPTIONS
} catch ( std::runtime_error& e ) {

View File

@ -1,14 +0,0 @@
#pragma once
#include <uf/config.h>
#include <uf/engine/entity/entity.h>
#include <uf/engine/scene/scene.h>
namespace uf {
namespace RenderBehavior {
UF_BEHAVIOR_DEFINE_TYPE();
UF_BEHAVIOR_DEFINE_TRAITS();
UF_BEHAVIOR_DEFINE_FUNCTIONS();
UF_BEHAVIOR_DEFINE_METADATA();
}
}

View File

@ -1,55 +0,0 @@
#pragma once
#include <uf/config.h>
#if !UF_USE_NCURSES
#include <uf/utils/memory/string.h>
namespace ext {
class UF_API Ncurses {
protected:
bool m_initialized;
bool m_initializeOnCtor = false;
void* m_window;
int m_timeout;
public:
// C-tor/D-tor
UF_API_CALL Ncurses();
~Ncurses();
// On-demand C-tor/D-tor
void UF_API_CALL initialize();
bool UF_API_CALL initialized();
void UF_API_CALL terminate();
// API (original named)
void UF_API_CALL getYX(int& row, int& column);
void UF_API_CALL getMaxYX(int& row, int& column);
void UF_API_CALL move(int row, int column);
void UF_API_CALL move(int toRow, int toColumn, int& row, int& column);
void UF_API_CALL refresh();
void UF_API_CALL clrToEol();
void UF_API_CALL clrToBot();
int UF_API_CALL getCh();
void UF_API_CALL delCh();
void UF_API_CALL addCh( char c );
void UF_API_CALL addStr(const char* c_str);
void UF_API_CALL addStr(const uf::stl::string str);
void UF_API_CALL attrOn(int att);
void UF_API_CALL attrOff(int att);
bool UF_API_CALL hasColors();
bool UF_API_CALL startColor();
void UF_API_CALL initPair( short id, short fore, short back );
// API (different named)
inline void UF_API_CALL clear(bool toBottom = true) { toBottom ? this->clrToBot() : this->clrToEol(); }
inline int UF_API_CALL getChar() { return this->getCh(); }
inline void UF_API_CALL delChar() { this->delCh(); }
inline void UF_API_CALL addChar( char c ) { this->addCh( c ); }
inline void UF_API_CALL addString( const uf::stl::string& str ) { this->addStr( str.c_str() ); }
inline void UF_API_CALL attribute(int att, bool on = true) { on ? this->attrOn(att) : this->attrOff(att); }
};
extern UF_API ext::Ncurses ncurses;
}
#endif

View File

@ -76,6 +76,7 @@ namespace ext {
Buffer buffer{};
size_t instanceID{};
bool aliased = false;
};
}
}

View File

@ -160,6 +160,10 @@ namespace ext {
return updateStorage(name, (const void*) userdata, userdata.size() );
}
void setSpecializationConstants( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values );
void setDescriptorCounts( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values );
/*
uf::Serializer getUniformJson( const uf::stl::string& name, bool cache = true );
bool updateUniform( const uf::stl::string& name, const ext::json::Value& payload );

View File

@ -19,10 +19,10 @@ namespace ext {
} filter;
struct {
VkSamplerAddressMode u = VK_SAMPLER_ADDRESS_MODE_REPEAT, v = VK_SAMPLER_ADDRESS_MODE_REPEAT, w = VK_SAMPLER_ADDRESS_MODE_REPEAT;
VkBool32 unnormalizedCoordinates = VK_FALSE;
bool unnormalizedCoordinates = VK_FALSE;
} addressMode;
struct {
VkBool32 compareEnable = VK_FALSE;
bool compareEnable = VK_FALSE;
VkCompareOp compareOp = VK_COMPARE_OP_ALWAYS;
VkSamplerMipmapMode mode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
float lodBias = 0.0f;
@ -30,9 +30,13 @@ namespace ext {
float max = 0.0f;
} mip;
struct {
VkBool32 enabled = VK_TRUE;
bool enabled = VK_TRUE;
float max = 16.0f;
} anisotropy;
struct {
bool enabled = false;
VkSamplerReductionMode mode = {};
} reduction;
VkDescriptorImageInfo info;
} descriptor = {};

View File

@ -163,6 +163,8 @@ namespace uf {
template<typename T, size_t N> pod::Vector<T,N>& decode( const ext::json::Value& v, pod::Vector<T,N>& ); // Parses a JSON value into a vector
template<typename T, size_t N> pod::Vector<T,N> decode( const ext::json::Value& v, const pod::Vector<T,N>& = {} ); // Parses a JSON value into a vector
template<typename T> typename T::type_t /*UF_API*/ mips( const T& size ); // Calculate amount of mips to use given a size
}
}

View File

@ -463,13 +463,12 @@ T /*UF_API*/ uf::vector::cross( const T& a, const T& b ) {
}
template<typename T> // Normalizes a vector
uf::stl::string /*UF_API*/ uf::vector::toString( const T& v ) {
uint_fast8_t size = T::size;
uf::stl::stringstream ss;
ss << "Vector(";
#pragma unroll // GCC unroll T::size
for ( auto i = 0; i < size; ++i ) {
for ( auto i = 0; i < T::size; ++i ) {
ss << v[i];
if ( i + 1 < size ) ss << ", ";
if ( i + 1 < T::size ) ss << ", ";
}
ss << ")";
return ss.str();
@ -521,6 +520,15 @@ pod::Vector<T,N> /*UF_API*/ uf::vector::decode( const ext::json::Value& json, co
}
return v;
}
template<typename T>
typename T::type_t /*UF_API*/ uf::vector::mips( const T& size ) {
typename T::type_t max = 0;
#pragma unroll // GCC unroll T::size
for ( auto i = 0; i < T::size; ++i ) max = std::max(max, size[i]);
return static_cast<uint32_t>(std::floor(std::log2(max))) + 1;
}
#if !__clang__ && __GNUC__
#pragma GCC pop_options
#endif

View File

@ -296,7 +296,7 @@ namespace ext {
uint32_t renderTarget = 0;
uint32_t subpass = 0;
uint32_t aux = 0;
struct {
size_t width = 1;

View File

@ -133,7 +133,7 @@ uf::Entity* uf::Entity::globalFindByUid( size_t uid ) {
}
{
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( uf::Entity* entity : graph ) {
if ( entity->getUid() == uid ) return entity;
}
@ -148,7 +148,7 @@ uf::Entity* uf::Entity::globalFindByName( const uf::stl::string& name ) {
}
{
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( uf::Entity* entity : graph ) {
if ( entity->getName() == name ) return entity;
}

View File

@ -195,11 +195,9 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
shader.buffers.emplace_back( uf::graph::storage.buffers.joint.alias() );
#if UF_USE_VULKAN
uint32_t maxPasses = 6;
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses);
}
shader.setSpecializationConstants({
{ "PASSES", maxPasses }
});
#endif
}
{
@ -214,19 +212,12 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
#if UF_USE_VULKAN
uint32_t maxTextures = graph.textures.size(); // texture2Ds;
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures;
}
}
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures },
});
#endif
}
#if UF_USE_VULKAN
@ -253,7 +244,7 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
shader.buffers.emplace_back( indirect->alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.instance.alias() );
shader.aliasAttachment("depth");
shader.aliasAttachment("depthPyramid");
}
}
if ( geometryShaderFilename != "" && uf::renderer::device.enabledFeatures.geometryShader ) {
@ -268,21 +259,15 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "depth");
graphic.material.metadata.autoInitializeUniformBuffers = true;
{
uint32_t maxTextures = graph.textures.size(); // texture2Ds;
auto& shader = graphic.material.getShader("fragment", "depth");
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures;
}
}
uint32_t maxTextures = graph.textures.size(); // texture2Ds;
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures },
});
shader.buffers.emplace_back( uf::graph::storage.buffers.drawCommands.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.instance.alias() );
@ -320,23 +305,17 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
uint32_t maxCascades = texture3Ds / voxelTypes;
auto& shader = graphic.material.getShader("fragment", uf::renderer::settings::pipelines::names::vxgi);
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures);
else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures;
else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
}
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures },
{ "CASCADES", maxCascades },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures },
{ "voxelId", maxCascades },
{ "voxelUv", maxCascades },
{ "voxelNormal", maxCascades },
{ "voxelRadiance", maxCascades },
});
shader.buffers.emplace_back( uf::graph::storage.buffers.drawCommands.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.instance.alias() );
@ -353,6 +332,11 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
uf::stl::string vertexShaderFilename = uf::io::resolveURI("/graph/baking/vert.spv");
uf::stl::string geometryShaderFilename = uf::io::resolveURI("/graph/baking/geom.spv");
uf::stl::string fragmentShaderFilename = uf::io::resolveURI("/graph/baking/frag.spv");
std::pair<bool, uf::stl::string> settings[] = {
{ uf::renderer::settings::pipelines::rt, "rt.frag" },
};
FOR_ARRAY(settings) if ( settings[i].first ) fragmentShaderFilename = uf::string::replace( fragmentShaderFilename, "frag", settings[i].second );
graphic.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "baking");
// graphic.material.attachShader(geometryShaderFilename, uf::renderer::enums::Shader::GEOMETRY, "baking");
graphic.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "baking");
@ -362,11 +346,9 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
uint32_t maxPasses = 6;
auto& shader = graphic.material.getShader("vertex", "baking");
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "PASSES" ) sc.value.ui = (specializationConstants[sc.index] = maxPasses);
}
shader.setSpecializationConstants({
{ "PASSES", maxPasses },
});
// shader.buffers.emplace_back( uf::graph::storage.buffers.camera.alias() );
// shader.buffers.emplace_back( uf::graph::storage.buffers.drawCommands.alias() );
@ -383,20 +365,14 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(128);
auto& shader = graphic.material.getShader("fragment", "baking");
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxCubemaps);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxCubemaps;
}
}
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures },
{ "CUBEMAPS", maxCubemaps },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures },
{ "samplerCubemaps", maxCubemaps },
});
shader.buffers.emplace_back( uf::graph::storage.buffers.drawCommands.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.instance.alias() );
@ -457,9 +433,6 @@ void uf::graph::initializeGraphics( pod::Graph& graph, uf::Object& entity, uf::M
}
#endif
// uf::instantiator::bind( "GraphBehavior", entity );
// uf::instantiator::unbind( "RenderBehavior", entity );
graphic.process = true;
}
@ -1167,7 +1140,6 @@ void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent )
}
}
if ( (graph.metadata["renderer"]["separate"].as<bool>()) && graph.metadata["renderer"]["render"].as<bool>() ) {
// uf::instantiator::bind("RenderBehavior", entity);
uf::graph::initializeGraphics( graph, entity, mesh );
}

View File

@ -50,153 +50,8 @@ void uf::GraphBehavior::initialize( uf::Object& self ) {
});
}
void uf::GraphBehavior::destroy( uf::Object& self ) {}
void uf::GraphBehavior::tick( uf::Object& self ) {
#if 0
if ( this->hasComponent<pod::Graph>() ) {
auto& graph = this->getComponent<pod::Graph>();
uf::graph::update( graph );
}
/* Update animations */ if ( this->hasComponent<pod::Graph>() ) {
auto& graph = this->getComponent<pod::Graph>();
// if ( graph.metadata["renderer"]["skinned"].as<bool>() ) uf::graph::update( graph );
}
if ( !this->hasComponent<uf::Graphic>() ) return;
const auto& scene = uf::scene::getCurrentScene();
const auto& metadata = this->getComponent<uf::Serializer>();
const auto& graphic = this->getComponent<uf::Graphic>();
const auto& controller = scene.getController();
const auto& camera = controller.getComponent<uf::Camera>();
const auto& transform = this->getComponent<pod::Transform<>>();
if ( !graphic.initialized ) return;
const auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
auto& graph = objectWithGraph->getComponent<pod::Graph>();
#if UF_USE_OPENGL
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
auto& mesh = this->getComponent<pod::Graph::Mesh>();
if ( !(graph.metadata["renderer"]["separate"].as<bool>()) ) {
uf::stl::vector<pod::Matrix4f> instances( graph.nodes.size() );
for ( size_t i = 0; i < graph.nodes.size(); ++i ) {
auto& node = graph.nodes[i];
instances[i] = uf::transform::model( node.entity ? node.entity->getComponent<pod::Transform<>>() : node.transform );
}
shader.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance );
shader.execute( graphic, mesh.attributes.vertex.pointer );
} else if ( graph.metadata["renderer"]["skinned"].as<bool>() ) {
shader.execute( graphic, mesh.attributes.vertex.pointer );
}
}
#elif UF_USE_VULKAN
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
if ( !(graph.metadata["renderer"]["separate"].as<bool>()) ) {
uf::stl::vector<pod::Matrix4f> instances( graph.nodes.size() );
for ( size_t i = 0; i < graph.nodes.size(); ++i ) {
auto& node = graph.nodes[i];
instances[i] = uf::transform::model( node.entity ? node.entity->getComponent<pod::Transform<>>() : node.transform );
}
shader.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance /*storageBuffer*/ );
} else {
struct UniformDescriptor {
pod::Matrix4f model;
};
#if UF_UNIFORMS_REUSE
auto& uniform = shader.getUniform("UBO");
auto& uniforms = uniform.get<UniformDescriptor>();
uniforms = {
.model = uf::transform::model( transform );
// .color = uf::vector::decode( metadata["color"], pod::Vector4f{1,1,1,1} ),
};
shader.updateUniform( "UBO", uniform );
#else
UniformDescriptor uniforms = {
.model = uf::transform::model( transform ),
// .color = uf::vector::decode( metadata["color"], pod::Vector4f{1,1,1,1} ),
};
shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") );
#endif
}
}
#if 0
if ( graphic.material.hasShader("vertex") && !(graph.metadata["renderer"]["separate"].as<bool>()) ) {
auto& shader = graphic.material.getShader("vertex");
uf::stl::vector<pod::Matrix4f> instances( graph.nodes.size() );
for ( size_t i = 0; i < graph.nodes.size(); ++i ) {
auto& node = graph.nodes[i];
instances[i] = node.entity ? uf::transform::model( node.entity->getComponent<pod::Transform<>>() ) : uf::transform::model( node.transform );
}
auto& storageBuffer = *graphic.getStorageBuffer("Models");
shader.updateBuffer( (const void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.buffers.instance /*storageBuffer*/ );
}
#endif
#endif
#endif
}
void uf::GraphBehavior::render( uf::Object& self ) {
#if 0
/* Update uniforms */
if ( !this->hasComponent<uf::Graphic>() ) return;
const auto& scene = uf::scene::getCurrentScene();
const auto& metadata = this->getComponent<uf::Serializer>();
const auto& graphic = this->getComponent<uf::Graphic>();
const auto& controller = scene.getController();
const auto& camera = controller.getComponent<uf::Camera>();
const auto& transform = this->getComponent<pod::Transform<>>();
if ( !graphic.initialized ) return;
#if UF_USE_OPENGL
const auto* objectWithGraph = this;
while ( objectWithGraph != &scene ) {
if ( objectWithGraph->hasComponent<pod::Graph>() ) break;
objectWithGraph = &objectWithGraph->getParent().as<uf::Object>();
}
if ( !objectWithGraph->hasComponent<pod::Graph>() ) return;
auto& graph = objectWithGraph->getComponent<pod::Graph>();
#if UF_UNIFORMS_REUSE
auto uniforms = graphic.getUniform();
pod::Uniform& uniform = *((pod::Uniform*) graphic.device->getBuffer(uniforms.buffer));
uniform = {
.modelView = !(graph.metadata["renderer"]["separate"].as<bool>()) ? camera.getView() : camera.getView() * uf::transform::model( transform ),
.projection = camera.getProjection();
};
graphic.updateUniform( (const void*) &uniform, sizeof(uniform) );
#else
pod::Uniform uniform = {
.modelView = !(graph.metadata["renderer"]["separate"].as<bool>()) ? camera.getView() : camera.getView() * uf::transform::model( transform ),
.projection = camera.getProjection(),
};
graphic.updateUniform( (const void*) &uniform, sizeof(uniform) );
#endif
#elif UF_USE_VULKAN
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
#if UF_UNIFORMS_REUSE
auto& uniform = shader.getUniform("Camera");
auto& uniforms = uniform.get<pod::Camera::Viewports>();
uniforms = camera.data().viewport;
shader.updateUniform("Camera", uniform);
#else
pod::Camera::Viewports uniforms = camera.data().viewport;
shader.updateBuffer( uniforms, shader.getUniformBuffer("Camera") );
#endif
}
#endif
#endif
}
void uf::GraphBehavior::tick( uf::Object& self ) {}
void uf::GraphBehavior::render( uf::Object& self ) {}
void uf::GraphBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {}
void uf::GraphBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) {}
#undef this

View File

@ -1,131 +0,0 @@
#include <uf/engine/object/behaviors/render.h>
#include <uf/engine/object/object.h>
#include <uf/engine/asset/asset.h>
#include <uf/engine/scene/scene.h>
#include <uf/utils/time/time.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/math/physics.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/mesh/mesh.h>
#include <uf/ext/gltf/gltf.h>
#define UF_UNIFORMS_UPDATE_WITH_JSON 0
UF_BEHAVIOR_REGISTER_CPP(uf::RenderBehavior)
UF_BEHAVIOR_TRAITS_CPP(uf::RenderBehavior, ticks = false, renders = false, multithread = false)
#define this (&self)
void uf::RenderBehavior::initialize( uf::Object& self ) {}
void uf::RenderBehavior::tick( uf::Object& self ) {
#if 0
if ( !this->hasComponent<uf::Graphic>() ) return;
const auto& metadata = this->getComponent<uf::Serializer>();
const auto& scene = uf::scene::getCurrentScene();
const auto& graphic = this->getComponent<uf::Graphic>();
const auto& transform = this->getComponent<pod::Transform<>>();
const auto& controller = scene.getController();
const auto& camera = controller.getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
#if UF_USE_OPENGL
/*
auto uniformBuffer = graphic.getUniform();
pod::Uniform& uniform = *((pod::Uniform*) uf::renderer::device.getBuffer(uniformBuffer.buffer));
uniform.projection = camera.getProjection();
uniform.modelView = camera.getView(); // * uf::transform::model( transform );
graphic.updateUniform( &uniform, sizeof(uniform) );
*/
#elif UF_USE_VULKAN
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
auto& uniform = shader.getUniform("UBO");
#if UF_UNIFORMS_UPDATE_WITH_JSON
// auto uniforms = shader.getUniformJson("UBO");
ext::json::Value uniforms;
uniforms["model"] = uf::matrix::encode( uf::transform::model( transform ) );
// uniforms["colors"] = metadata["color"];
shader.updateUniform("UBO", uniforms );
#else
struct UniformDescriptor {
pod::Matrix4f model;
};
#if UF_UNIFORMS_REUSE
auto& uniforms = uniform.get<UniformDescriptor>();
uniforms = {
.model = uf::transform::model( transform );
// .color = uf::vector::decode( metadata["color"], pod::Vector4f{ 1, 1, 1, 1 } ),
};
shader.updateUniform( "UBO", uniform );
#else
UniformDescriptor uniforms = {
.model = uf::transform::model( transform ),
// .color = uf::vector::decode( metadata["color"], pod::Vector4f{ 1, 1, 1, 1 } ),
};
shader.updateBuffer( uniforms, shader.getUniformBuffer("UBO") );
#endif
#endif
}
#endif
#endif
}
void uf::RenderBehavior::render( uf::Object& self ) {
#if 0
if ( !this->hasComponent<uf::Graphic>() ) return;
const auto& metadata = this->getComponent<uf::Serializer>();
const auto& scene = uf::scene::getCurrentScene();
const auto& graphic = this->getComponent<uf::Graphic>();
const auto& transform = this->getComponent<pod::Transform<>>();
const auto& controller = scene.getController();
const auto& camera = controller.getComponent<uf::Camera>();
if ( !graphic.initialized ) return;
#if UF_USE_OPENGL
#if UF_UNIFORMS_REUSE
auto uniforms = graphic.getUniform();
pod::Uniform& uniform = *((pod::Uniform*) uf::renderer::device.getBuffer(uniforms.buffer));
uniform = {
.modelView = camera.getView() * uf::transform::model( transform ),
.projection = camera.getProjection(),
};
graphic.updateUniform( &uniform, sizeof(uniform) );
#else
pod::Uniform uniform = {
.modelView = camera.getView() * uf::transform::model( transform ),
.projection = camera.getProjection(),
};
graphic.updateUniform( &uniform, sizeof(uniform) );
#endif
#elif UF_USE_VULKAN
if ( graphic.material.hasShader("vertex") ) {
auto& shader = graphic.material.getShader("vertex");
auto& uniform = shader.getUniform("Camera");
#if UF_UNIFORMS_UPDATE_WITH_JSON
// auto uniforms = shader.getUniformJson("Camera");
ext::json::Value uniforms;
ext::json::reserve( uniforms["viewport"], uf::camera::maxViews );
for ( uint_fast8_t i = 0; i < uf::camera::maxViews; ++i ) {
uniforms["viewport"][i]["view"] = uf::matrix::encode( camera.getView( i ) );
uniforms["viewport"][i]["projection"] = uf::matrix::encode( camera.getProjection( i ) );
}
shader.updateUniform("Camera", uniforms);
#else
#if UF_UNIFORMS_REUSE
auto& uniforms = uniform.get<pod::Camera::Viewports>();
uniforms = camera.data().viewport;
shader.updateUniform("Camera", uniform);
#else
pod::Camera::Viewports uniforms = camera.data().viewport;
shader.updateBuffer( uniforms, shader.getUniformBuffer("Camera") );
#endif
#endif
}
#endif
#endif
}
void uf::RenderBehavior::destroy( uf::Object& self ) {}
void uf::RenderBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {}
void uf::RenderBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ) {}
#undef this

View File

@ -15,6 +15,7 @@ uf::Scene::Scene() UF_BEHAVIOR_ENTITY_CPP_ATTACH(uf::Scene)
#define UF_SCENE_GLOBAL_GRAPH 1
#define UF_TICK_MULTITHREAD_OVERRIDE 0
#define UF_TICK_FROM_TASKS 1
#define UF_SCENE_INVALIDATE_IMMEDIATE 1
#if UF_SCENE_GLOBAL_GRAPH
namespace {
@ -61,20 +62,27 @@ void uf::Scene::invalidateGraph() {
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
#endif
metadata.invalidationQueued = true;
/*
metadata.cache.clear();
metadata.tasks.serial.clear();
metadata.tasks.parallel.clear();
metadata.graph.clear();
*/
}
const uf::stl::vector<uf::Entity*>& uf::Scene::getGraph() {
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
#endif
#if UF_SCENE_INVALIDATE_IMMEDIATE
if ( metadata.invalidationQueued ) {
metadata.invalidationQueued = false;
metadata.cache.clear();
metadata.graph.clear();
metadata.tasks.serial.clear();
metadata.tasks.parallel.clear();
}
#endif
if ( !metadata.graph.empty() ) return metadata.graph;
metadata.tasks.serial = uf::thread::schedule(false);
@ -89,7 +97,7 @@ const uf::stl::vector<uf::Entity*>& uf::Scene::getGraph() {
#if UF_TICK_FROM_TASKS
auto* self = (uf::Object*) entity;
auto& behaviorGraph = entity->getGraph();
auto/*&*/ behaviorGraph = entity->getGraph();
#if 1
#if UF_TICK_MULTITHREAD_OVERRIDE
for ( auto fun : behaviorGraph.tick.serial ) metadata.tasks.parallel.queue([=]{ fun(*self); });
@ -124,7 +132,7 @@ const uf::stl::vector<uf::Entity*>& uf::Scene::getGraph() {
return metadata.graph;
}
uf::stl::vector<uf::Entity*> uf::Scene::getGraph( bool reverse ) {
auto graph = this->getGraph();
auto/*&*/ graph = this->getGraph();
if ( reverse ) std::reverse( graph.begin(), graph.end() );
return graph;
}
@ -160,7 +168,7 @@ uf::Scene& uf::scene::loadScene( const uf::stl::string& name, const uf::Serializ
void uf::scene::unloadScene() {
uf::Scene* current = uf::scene::scenes.back();
// current->destroy();
auto graph = current->getGraph(true);
auto/*&*/ graph = current->getGraph(true);
for ( auto entity : graph ) entity->destroy();
uf::scene::scenes.pop_back();
}
@ -176,11 +184,20 @@ void uf::scene::invalidateGraphs() {
void uf::scene::tick() {
if ( scenes.empty() ) return;
#if !UF_SCENE_INVALIDATE_IMMEDIATE
if ( metadata.invalidationQueued ) {
metadata.invalidationQueued = false;
metadata.graph.clear();
metadata.tasks.serial.clear();
metadata.tasks.parallel.clear();
}
#endif
auto& scene = uf::scene::getCurrentScene();
#if !UF_SCENE_GLOBAL_GRAPH
auto& metadata = scene.getComponent<uf::SceneBehavior::Metadata>();
#endif
auto graph = scene.getGraph(true);
auto/*&*/ graph = scene.getGraph(true);
#if UF_TICK_FROM_TASKS
// copy because executing from the tasks erases them all
auto tasks = metadata.tasks;
@ -194,7 +211,8 @@ void uf::scene::tick() {
}
void uf::scene::render() {
if ( scenes.empty() ) return;
auto graph = uf::scene::getCurrentScene().getGraph(true);
auto& scene = uf::scene::getCurrentScene();
auto/*&*/ graph = scene.getGraph(true);
for ( auto entity : graph ) entity->render();
}
void uf::scene::destroy() {

View File

@ -59,7 +59,7 @@ void ext::opengl::RenderMode::createCommandBuffers() {
uf::stl::vector<ext::opengl::Graphic*> graphics;
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
ext::opengl::Graphic& graphic = entity->getComponent<uf::Graphic>();
@ -89,7 +89,7 @@ void ext::opengl::RenderMode::bindPipelines() {
uf::stl::vector<ext::opengl::Graphic*> graphics;
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
ext::opengl::Graphic& graphic = entity->getComponent<uf::Graphic>();

View File

@ -220,7 +220,7 @@ void ext::opengl::Texture::fromBuffers(
if ( this->mips == 0 ) {
this->mips = 1;
} else if ( this->depth == 1 ) {
this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
this->mips = uf::vector::mips( pod::Vector2ui{ texWidth, texHeight, texDepth } );
}
if ( this->mips > 1 ) {

View File

@ -458,10 +458,16 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
for ( auto* shader : shaders ) {
if ( shader->descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
auto& localSize = shader->metadata.definitions.localSize;
auto dispatch = pod::Vector3ui{
std::ceil( (float) width / localSize.x ),
std::ceil( (float) height / localSize.y ),
std::ceil( (float) depth / localSize.z ),
};
vkCmdDispatch(commandBuffer,
1 < localSize.x ? ((width / localSize.x) + 1) : 1,
1 < localSize.y ? ((height / localSize.y) + 1) : 1,
1 < localSize.z ? ((depth / localSize.z) + 1) : 1
dispatch.x,
dispatch.y,
dispatch.z
);
}
}
@ -480,6 +486,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
auto shaders = getShaders( graphic.material.shaders );
uf::stl::vector<VkWriteDescriptorSet> writeDescriptorSets;
uf::stl::vector<uf::renderer::AccelerationStructure> tlases;
struct Infos {
uf::stl::vector<VkDescriptorBufferInfo> uniform;
@ -646,14 +653,25 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
}
if ( !graphic.accelerationStructures.tops.empty() ) {
infos.accelerationStructure.emplace_back(graphic.accelerationStructures.tops[0].buffer.descriptor);
auto tlas = graphic.accelerationStructures.tops.front();
if ( tlas.handle != VK_NULL_HANDLE ) tlases.emplace_back(tlas);
}
for ( auto& info : infos.accelerationStructure ) {
if ( infos.accelerationStructure.empty() ) {
uf::stl::string renderModeName = uf::renderer::hasRenderMode("Compute:RT", true) ? "Compute:RT" : "";
auto& blitter = *(uf::renderer::getRenderMode(renderModeName, true).getBlitter());
if ( !blitter.accelerationStructures.tops.empty() ) {
tlases.emplace_back(blitter.accelerationStructures.tops.front());
}
}
for ( auto& tlas : tlases ) {
infos.accelerationStructure.emplace_back(tlas.buffer.descriptor);
auto& descriptorAccelerationStructureInfo = infos.accelerationStructureInfos.emplace_back();
descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
descriptorAccelerationStructureInfo.pAccelerationStructures = &graphic.accelerationStructures.tops[infos.accelerationStructureInfos.size()-1].handle;
descriptorAccelerationStructureInfo.pAccelerationStructures = &tlas.handle;
}
auto uniformBufferInfo = infos.uniform.begin();
@ -1958,11 +1976,13 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
void ext::vulkan::Graphic::destroy() {
if ( device ) {
for ( auto& as : accelerationStructures.bottoms ) {
if ( as.aliased ) continue;
uf::renderer::vkDestroyAccelerationStructureKHR(*device, as.handle, nullptr);
}
accelerationStructures.bottoms.clear();
for ( auto& as : accelerationStructures.tops ) {
if ( as.aliased ) continue;
uf::renderer::vkDestroyAccelerationStructureKHR(*device, as.handle, nullptr);
}
accelerationStructures.tops.clear();
@ -1996,69 +2016,8 @@ void ext::vulkan::GraphicDescriptor::parse( ext::json::Value& metadata ) {
}
ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() const {
size_t seed{};
#if 0
for ( auto i = 0; i < inputs.vertex.attributes.size(); ++i ) {
uf::hash( inputs.vertex.attributes[i].descriptor.format );
uf::hash( inputs.vertex.attributes[i].descriptor.offset );
}
for ( auto i = 0; i < inputs.index.attributes.size(); ++i ) {
uf::hash( inputs.index.attributes[i].descriptor.format );
uf::hash( inputs.index.attributes[i].descriptor.offset );
}
for ( auto i = 0; i < inputs.instance.attributes.size(); ++i ) {
uf::hash( inputs.instance.attributes[i].descriptor.format );
uf::hash( inputs.instance.attributes[i].descriptor.offset );
}
for ( auto i = 0; i < inputs.indirect.attributes.size(); ++i ) {
uf::hash( inputs.indirect.attributes[i].descriptor.format );
uf::hash( inputs.indirect.attributes[i].descriptor.offset );
}
#endif
uf::hash( seed, subpass, renderMode, renderTarget, pipeline, topology, cullMode, fill, lineWidth, frontFace, depth.test, depth.write, depth.operation, depth.bias.enable, depth.bias.constant, depth.bias.slope, depth.bias.clamp );
uf::hash( seed, aux, subpass, renderMode, renderTarget, pipeline, topology, cullMode, fill, lineWidth, frontFace, depth.test, depth.write, depth.operation, depth.bias.enable, depth.bias.constant, depth.bias.slope, depth.bias.clamp );
return seed;
#if 0
hash += std::hash<decltype(subpass)>{}(subpass);
if ( settings::invariant::individualPipelines )
hash += std::hash<decltype(renderMode)>{}(renderMode);
hash += std::hash<decltype(renderTarget)>{}(renderTarget);
hash += std::hash<decltype(pipeline)>{}(pipeline);
for ( auto i = 0; i < inputs.vertex.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.vertex.attributes[i].descriptor.format)>{}(inputs.vertex.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.vertex.attributes[i].descriptor.offset)>{}(inputs.vertex.attributes[i].descriptor.offset);
}
for ( auto i = 0; i < inputs.index.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.index.attributes[i].descriptor.format)>{}(inputs.index.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.index.attributes[i].descriptor.offset)>{}(inputs.index.attributes[i].descriptor.offset);
}
for ( auto i = 0; i < inputs.instance.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.instance.attributes[i].descriptor.format)>{}(inputs.instance.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.instance.attributes[i].descriptor.offset)>{}(inputs.instance.attributes[i].descriptor.offset);
}
/*
for ( auto i = 0; i < inputs.indirect.attributes.size(); ++i ) {
hash += std::hash<decltype(inputs.indirect.attributes[i].descriptor.format)>{}(inputs.indirect.attributes[i].descriptor.format);
hash += std::hash<decltype(inputs.indirect.attributes[i].descriptor.offset)>{}(inputs.indirect.attributes[i].descriptor.offset);
}
*/
hash += std::hash<decltype(topology)>{}(topology);
hash += std::hash<decltype(cullMode)>{}(cullMode);
hash += std::hash<decltype(fill)>{}(fill);
hash += std::hash<decltype(lineWidth)>{}(lineWidth);
hash += std::hash<decltype(frontFace)>{}(frontFace);
hash += std::hash<decltype(depth.test)>{}(depth.test);
hash += std::hash<decltype(depth.write)>{}(depth.write);
hash += std::hash<decltype(depth.operation)>{}(depth.operation);
hash += std::hash<decltype(depth.bias.enable)>{}(depth.bias.enable);
hash += std::hash<decltype(depth.bias.constant)>{}(depth.bias.constant);
hash += std::hash<decltype(depth.bias.slope)>{}(depth.bias.slope);
hash += std::hash<decltype(depth.bias.clamp)>{}(depth.bias.clamp);
return hash;
#endif
}
#endif

View File

@ -211,7 +211,7 @@ void ext::vulkan::RenderMode::createCommandBuffers() {
uf::stl::vector<ext::vulkan::Graphic*> graphics;
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
@ -284,7 +284,7 @@ void ext::vulkan::RenderMode::bindPipelines() {
uf::stl::vector<ext::vulkan::Graphic*> graphics;
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();

View File

@ -23,6 +23,8 @@
namespace {
const uf::stl::string DEFERRED_MODE = "compute";
ext::vulkan::Texture depthPyramid;
uf::stl::vector<VkImageView> depthPyramidViews;
}
#include "./transition.inl"
@ -50,10 +52,10 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
renderTarget.views = metadata.eyes;
size_t msaa = ext::vulkan::settings::msaa;
struct {
size_t id, bary, depth, uv, normal;
size_t color, bright, motion, scratch, output;
size_t depthPyramid;
} attachments = {};
bool blend = true; // !ext::vulkan::settings::invariant::deferredSampling;
@ -99,6 +101,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
/*.blend = */false,
/*.samples = */msaa,
//*.mips = */1,
});
// output buffers
attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{
@ -130,6 +133,14 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
/*.blend = */false,
/*.samples = */1,
});
attachments.depthPyramid = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format = */VK_FORMAT_R32_SFLOAT,
/*.layout = */ VK_IMAGE_LAYOUT_GENERAL,
/*.usage = */ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.blend = */false,
/*.samples = */1,
/*.mips = */1
});
metadata.attachments["id"] = attachments.id;
@ -143,6 +154,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
#endif
metadata.attachments["depth"] = attachments.depth;
metadata.attachments["depthPyramid"] = attachments.depthPyramid;
metadata.attachments["color"] = attachments.color;
metadata.attachments["bright"] = attachments.bright;
metadata.attachments["scratch"] = attachments.scratch;
@ -224,22 +236,13 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{uf::io::resolveURI(vertexShaderFilename), uf::renderer::enums::Shader::VERTEX},
{uf::io::resolveURI(fragmentShaderFilename), uf::renderer::enums::Shader::FRAGMENT}
});
}
if ( blitter.material.hasShader("fragment") ) {
auto& shader = blitter.material.getShader("fragment");
if ( !settings::pipelines::fsr ) {
shader.aliasAttachment("output", this);
}
/*
if ( settings::pipelines::fsr ) {
auto& renderMode = ext::vulkan::getRenderMode("Swapchain", true);
shader.aliasAttachment("fsr", &renderMode, VK_IMAGE_LAYOUT_GENERAL);
} else {
shader.aliasAttachment("output", this);
}
*/
}
if ( settings::pipelines::deferred ) {
if ( DEFERRED_MODE == "compute" ) {
uf::stl::string computeShaderFilename = "comp.spv"; {
@ -267,19 +270,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
blitter.material.attachShader(uf::io::resolveURI(fragmentShaderFilename), uf::renderer::enums::Shader::FRAGMENT, "deferred");
UF_MSG_DEBUG("Using deferred shader: {}", fragmentShaderFilename);
}
}
if ( settings::pipelines::bloom ) {
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom/comp.spv");
blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom");
auto& shader = blitter.material.getShader("compute", "bloom");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("bright", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
}
if ( settings::pipelines::deferred ) {
auto& shader = blitter.material.getShader(DEFERRED_MODE, "deferred");
size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>(512);
@ -288,6 +279,20 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(128);
size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures2D },
{ "CUBEMAPS", maxTexturesCube },
{ "CASCADES", maxCascades },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures2D },
{ "samplerCubemaps", maxTexturesCube },
{ "voxelId", maxCascades },
{ "voxelUv", maxCascades },
{ "voxelNormal", maxCascades },
{ "voxelRadiance", maxCascades },
});
// shader.buffers.emplace_back( uf::graph::storage.buffers.camera.alias() );
// shader.buffers.emplace_back( uf::graph::storage.buffers.joint.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.drawCommands.alias() );
@ -297,46 +302,6 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
shader.buffers.emplace_back( uf::graph::storage.buffers.texture.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.light.alias() );
if ( ext::vulkan::settings::pipelines::vxgi ) {
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube);
else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
}
} else {
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
}
}
}
}
if ( settings::pipelines::deferred && blitter.material.hasShader(DEFERRED_MODE, "deferred") ) {
auto& shader = blitter.material.getShader(DEFERRED_MODE, "deferred");
shader.aliasAttachment("id", this);
#if BARYCENTRIC
#if !BARYCENTRIC_CALCULATE
@ -352,7 +317,78 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
shader.aliasAttachment("bright", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("motion", this, VK_IMAGE_LAYOUT_GENERAL);
}
if ( settings::pipelines::bloom ) {
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/bloom/comp.spv");
blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "bloom");
auto& shader = blitter.material.getShader("compute", "bloom");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("bright", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
}
if ( settings::pipelines::culling ) {
uf::stl::string computeShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/depth-pyramid/comp.spv");
blitter.material.attachShader(computeShaderFilename, uf::renderer::enums::Shader::COMPUTE, "depth-pyramid");
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
auto attachment = this->getAttachment("depth");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
shader.setSpecializationConstants({
{ "MIPS", mips - 1 },
});
shader.setDescriptorCounts({
{ "inImage", mips - 1 },
{ "outImage", mips - 1 },
});
shader.aliasAttachment("depth", this);
ext::vulkan::Texture2D source; source.aliasAttachment( this->getAttachment("depthPyramid") );
source.sampler.descriptor.reduction.enabled = true;
source.sampler.descriptor.reduction.mode = VK_SAMPLER_REDUCTION_MODE_MIN;
for ( auto& view : ::depthPyramidViews ) {
vkDestroyImageView(device.logicalDevice, view, nullptr);
}
::depthPyramidViews.clear();
::depthPyramidViews.resize(mips-1);
shader.textures.clear();
for ( auto i = 1; i < mips; ++i ) {
auto& view = ::depthPyramidViews[i-1];
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.pNext = NULL;
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
viewCreateInfo.subresourceRange.baseMipLevel = i;
viewCreateInfo.subresourceRange.layerCount = 1;
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCreateInfo.viewType = source.viewType;
viewCreateInfo.format = source.format;
viewCreateInfo.image = source.image;
VK_CHECK_RESULT(vkCreateImageView(device.logicalDevice, &viewCreateInfo, nullptr, &view));
if ( i + 1 < mips ) {
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
}
}
for ( auto i = 1; i < mips; ++i ) {
auto& view = ::depthPyramidViews[i-1];
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
}
}
if ( !blitter.hasPipeline( blitter.descriptor ) ){
blitter.initializePipeline( blitter.descriptor );
}
@ -386,6 +422,16 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
blitter.initializePipeline( descriptor );
}
}
if ( settings::pipelines::culling ) {
descriptor.aux = uf::vector::mips( pod::Vector2ui{ width, height } );
descriptor.pipeline = "depth-pyramid";
descriptor.subpass = 0;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( !blitter.hasPipeline( descriptor ) ) {
blitter.initializePipeline( descriptor );
}
}
}
}
}
@ -395,22 +441,78 @@ void ext::vulkan::DeferredRenderMode::tick() {
bool resized = (this->width == 0 && this->height == 0 && ext::vulkan::states::resized) || this->resized;
bool rebuild = resized || ext::vulkan::states::rebuild || this->rebuild;
uint32_t width = this->width > 0 ? this->width : (ext::vulkan::settings::width * this->scale);
uint32_t height = this->height > 0 ? this->height : (ext::vulkan::settings::height * this->scale);
if ( resized ) {
this->resized = false;
rebuild = true;
renderTarget.initialize( *renderTarget.device );
if ( settings::pipelines::culling ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
auto attachment = this->getAttachment("depth");
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
shader.setSpecializationConstants({
{ "MIPS", mips - 1 },
});
shader.setDescriptorCounts({
{ "inImage", mips - 1 },
{ "outImage", mips - 1 },
});
ext::vulkan::Texture2D source; source.aliasAttachment( this->getAttachment("depthPyramid") );
source.sampler.descriptor.reduction.enabled = true;
source.sampler.descriptor.reduction.mode = VK_SAMPLER_REDUCTION_MODE_MIN;
for ( auto& view : ::depthPyramidViews ) {
vkDestroyImageView(device->logicalDevice, view, nullptr);
}
::depthPyramidViews.clear();
::depthPyramidViews.resize(mips-1);
shader.textures.clear();
for ( auto i = 1; i < mips; ++i ) {
auto& view = ::depthPyramidViews[i-1];
VkImageViewCreateInfo viewCreateInfo = {};
viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCreateInfo.pNext = NULL;
viewCreateInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
viewCreateInfo.subresourceRange.baseMipLevel = i;
viewCreateInfo.subresourceRange.layerCount = 1;
viewCreateInfo.subresourceRange.levelCount = 1;
viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCreateInfo.viewType = source.viewType;
viewCreateInfo.format = source.format;
viewCreateInfo.image = source.image;
VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view));
if ( i + 1 < mips ) {
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
}
}
for ( auto i = 1; i < mips; ++i ) {
auto& view = ::depthPyramidViews[i-1];
auto& texture = shader.textures.emplace_back();
texture.aliasTexture( source );
texture.view = view;
texture.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
texture.updateDescriptors();
}
}
}
// update blitter descriptor set
if ( rebuild && blitter.initialized ) {
uint32_t width = this->width > 0 ? this->width : (ext::vulkan::settings::width * this->scale);
uint32_t height = this->height > 0 ? this->height : (ext::vulkan::settings::height * this->scale);
// UF_MSG_DEBUG("{} x {} ({:3f}%)", width, height, this->scale*100.0f);
if ( blitter.hasPipeline( blitter.descriptor ) ){
blitter.getPipeline( blitter.descriptor ).update( blitter, blitter.descriptor );
} else {
blitter.initializePipeline( blitter.descriptor );
}
{
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = "";
@ -429,6 +531,8 @@ void ext::vulkan::DeferredRenderMode::tick() {
}
if ( blitter.hasPipeline( descriptor ) ) {
blitter.getPipeline( descriptor ).update( blitter, descriptor );
} else {
blitter.initializePipeline( descriptor );
}
}
@ -438,6 +542,20 @@ void ext::vulkan::DeferredRenderMode::tick() {
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( blitter.hasPipeline( descriptor ) ) {
blitter.getPipeline( descriptor ).update( blitter, descriptor );
} else {
blitter.initializePipeline( descriptor );
}
}
if ( settings::pipelines::culling ) {
descriptor.aux = uf::vector::mips( pod::Vector2ui{ width, height } );
descriptor.pipeline = "depth-pyramid";
descriptor.subpass = 0;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
if ( blitter.hasPipeline( descriptor ) ) {
blitter.getPipeline( descriptor ).update( blitter, descriptor );
} else {
blitter.initializePipeline( descriptor );
}
}
}
@ -543,7 +661,8 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
}
bool shouldRecord = true; // ( settings::pipelines::rt && !sceneMetadataJson["system"]["config"]["engine"]["scenes"]["rt"]["full"].as<bool>() ) || !settings::pipelines::rt;
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
auto commandBuffer = commands[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
// Fill GBuffer
{
VkRenderPassBeginInfo renderPassBeginInfo = {};
@ -576,7 +695,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
// transition layers for read
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 0 );
layer->pipelineBarrier( commandBuffer, 0 );
}
for ( auto& pipeline : metadata.pipelines ) {
@ -585,16 +704,22 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
if ( graphic->descriptor.renderMode != this->getName() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
descriptor.pipeline = pipeline;
graphic->record( commands[i], descriptor, 0, metadata.eyes );
if ( pipeline == uf::renderer::settings::pipelines::names::culling ) {
descriptor.bind.width = graphic->descriptor.inputs.indirect.count;
descriptor.bind.height = 1;
descriptor.bind.depth = 1;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
}
graphic->record( commandBuffer, descriptor, 0, metadata.eyes );
}
}
// pre-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i], i );
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commandBuffer, i );
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
// render to geometry buffers
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
size_t currentPass = 0;
@ -603,10 +728,10 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
// only draw graphics that are assigned to this type of render mode
if ( graphic->descriptor.renderMode != this->getName() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
graphic->record( commands[i], descriptor, eye, currentDraw++ );
graphic->record( commandBuffer, descriptor, eye, currentDraw++ );
}
if ( eye + 1 < metadata.eyes ) {
vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE); ++currentSubpass;
vkCmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE); ++currentSubpass;
}
}
// skip deferred pass if RT is enabled, we still process geometry for a depth buffer
@ -619,13 +744,13 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
descriptor.pipeline = "deferred";
descriptor.subpass = currentSubpass;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_GRAPHICS;
blitter.record(commands[i], descriptor, eye, currentDraw++);
blitter.record(commandBuffer, descriptor, eye, currentDraw++);
}
if ( eye + 1 < metadata.eyes ) {
vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE); ++currentSubpass;
vkCmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE); ++currentSubpass;
}
}
vkCmdEndRenderPass(commands[i]);
vkCmdEndRenderPass(commandBuffer);
if ( settings::pipelines::deferred && DEFERRED_MODE == "compute" && blitter.material.hasShader(DEFERRED_MODE, "deferred") ) {
auto& shader = blitter.material.getShader(DEFERRED_MODE, "deferred");
@ -639,13 +764,13 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
descriptor.subpass = 0;
// transition attachments to general attachments for imageStore
::transitionAttachmentsTo( this, shader, commands[i] );
::transitionAttachmentsTo( this, shader, commandBuffer );
// dispatch compute shader
blitter.record(commands[i], descriptor, 0, 0);
blitter.record(commandBuffer, descriptor, 0, 0);
// transition attachments back to shader read layouts
::transitionAttachmentsFrom( this, shader, commands[i] );
::transitionAttachmentsFrom( this, shader, commandBuffer );
}
if ( settings::pipelines::bloom && blitter.material.hasShader("compute", "bloom") ) {
@ -660,25 +785,77 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
descriptor.subpass = 0;
// transition attachments to general attachments for imageStore
::transitionAttachmentsTo( this, shader, commands[i] );
::transitionAttachmentsTo( this, shader, commandBuffer );
// dispatch compute shader
VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
blitter.record(commands[i], descriptor, 0, 1);
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
blitter.record(commands[i], descriptor, 0, 2);
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
blitter.record(commands[i], descriptor, 0, 3);
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
blitter.record(commandBuffer, descriptor, 0, 1);
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
blitter.record(commandBuffer, descriptor, 0, 2);
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
blitter.record(commandBuffer, descriptor, 0, 3);
// transition attachments back to shader read layouts
::transitionAttachmentsFrom( this, shader, commands[i] );
::transitionAttachmentsFrom( this, shader, commandBuffer );
}
// construct depth-pyramid
if ( settings::pipelines::culling && blitter.material.hasShader("compute", "depth-pyramid") ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
// auto mips = attachment.descriptor.mips; // uf::vector::mips( pod::Vector2ui{ renderTarget.width, renderTarget.height } );
auto mips = uf::vector::mips( pod::Vector2ui{ width, height } );
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.renderMode = "";
descriptor.aux = uf::vector::mips( pod::Vector2ui{ width, height } );
descriptor.pipeline = "depth-pyramid";
descriptor.bind.width = width;
descriptor.bind.height = height;
descriptor.bind.depth = metadata.eyes;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
descriptor.subpass = 0;
/*
// transition attachments to general attachments for imageStore
VkImageSubresourceRange subresourceRange;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
subresourceRange.baseArrayLayer = 0;
subresourceRange.layerCount = mips;
subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
subresourceRange.layerCount = this->metadata.eyes;
auto& attachment = this->getAttachment("depth");
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, subresourceRange );
*/
// dispatch compute shader
VkMemoryBarrier memoryBarrier{VK_STRUCTURE_TYPE_MEMORY_BARRIER};
memoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
memoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
for ( auto i = 0; i < mips - 1; ++i ) {
descriptor.bind.width = width >> i;
descriptor.bind.height = height >> i;
if ( descriptor.bind.width < 1 ) descriptor.bind.width = 1;
if ( descriptor.bind.height < 1 ) descriptor.bind.height = 1;
blitter.record(commandBuffer, descriptor, 0, i);
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
}
/*
// transition attachments to general attachments for imageStore
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, subresourceRange );
*/
}
// post-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i], i );
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commandBuffer, i );
#if 0
if ( this->hasAttachment("depth") ) {
@ -693,16 +870,16 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
#if 1
imageMemoryBarrier.subresourceRange.layerCount = metadata.eyes;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
uf::renderer::Texture::setImageLayout( commands[i], attachment.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageMemoryBarrier.subresourceRange );
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageMemoryBarrier.subresourceRange );
#endif
for ( size_t eye = 0; eye < metadata.eyes; ++eye ) {
texture.generateMipmaps(commands[i], eye);
texture.generateMipmaps(commandBuffer, eye);
}
#if 1
uf::renderer::Texture::setImageLayout( commands[i], attachment.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, imageMemoryBarrier.subresourceRange );
uf::renderer::Texture::setImageLayout( commandBuffer, attachment.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, imageMemoryBarrier.subresourceRange );
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarrier.subresourceRange.layerCount = 1;
#endif
@ -710,11 +887,11 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
#endif
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 1 );
layer->pipelineBarrier( commandBuffer, 1 );
}
}
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
}
}

View File

@ -333,15 +333,30 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
}
if ( metadata.type == uf::renderer::settings::pipelines::names::vxgi ) {
auto& scene = uf::scene::getCurrentScene();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
auto& shader = blitter.material.getShader("compute");
size_t maxLights = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["max"].as<size_t>(512);
size_t maxTextures2D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["2D"].as<size_t>(512);
size_t maxTexturesCube = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["cube"].as<size_t>(128);
size_t maxTextures3D = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["textures"]["max"]["3D"].as<size_t>(1);
size_t maxCascades = sceneMetadataJson["system"]["config"]["engine"]["scenes"]["vxgi"]["cascades"].as<size_t>(16);
auto& shader = blitter.material.getShader("compute");
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures2D },
{ "CUBEMAPS", maxTexturesCube },
{ "CASCADES", maxCascades },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures2D },
{ "samplerCubemaps", maxTexturesCube },
{ "voxelId", maxCascades },
{ "voxelUv", maxCascades },
{ "voxelNormal", maxCascades },
{ "voxelRadiance", maxCascades },
});
// shader.buffers.emplace_back( uf::graph::storage.buffers.camera.alias() );
// shader.buffers.emplace_back( uf::graph::storage.buffers.joint.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.drawCommands.alias() );
@ -350,26 +365,6 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
shader.buffers.emplace_back( uf::graph::storage.buffers.material.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.texture.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.light.alias() );
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( sc.name == "TEXTURES" ) sc.value.ui = (specializationConstants[sc.index] = maxTextures2D);
else if ( sc.name == "CUBEMAPS" ) sc.value.ui = (specializationConstants[sc.index] = maxTexturesCube);
else if ( sc.name == "CASCADES" ) sc.value.ui = (specializationConstants[sc.index] = maxCascades);
}
for ( auto pair : shader.metadata.definitions.textures ) {
auto& tx = pair.second;
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
if ( tx.name == "samplerTextures" ) layout.descriptorCount = maxTextures2D;
else if ( tx.name == "samplerCubemaps" ) layout.descriptorCount = maxTexturesCube;
else if ( tx.name == "voxelId" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelUv" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelNormal" ) layout.descriptorCount = maxCascades;
else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
}
} else if ( metadata.type == uf::renderer::settings::pipelines::names::rt ) {
#if 0
auto& shader = blitter.material.getShader("fragment");
@ -490,7 +485,8 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
auto& commands = getCommands();
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
auto& commandBuffer = commands[i];
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
{
VkRenderPassBeginInfo renderPassBeginInfo = {};
@ -522,15 +518,16 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
size_t subpasses = renderTarget.passes.size();
size_t currentPass = 0;
// pre-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i], i );
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commandBuffer, i );
if ( this->getName() == "Compute" ) {
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getTarget() ) continue;
if ( graphic->descriptor.pipeline != uf::renderer::settings::pipelines::names::rt ) continue;
graphic->record( commands[i] );
graphic->record( commandBuffer );
}
} else {
#if 0
for ( auto& pipeline : metadata.pipelines ) {
if ( pipeline == metadata.pipeline ) continue;
for ( auto graphic : graphics ) {
@ -538,31 +535,54 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass);
descriptor.pipeline = pipeline;
if ( pipeline == "rt" ) descriptor.bind.point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
graphic->record( commands[i], descriptor, 0, metadata.type == uf::renderer::settings::pipelines::names::vxgi ? 0 : MIN(subpasses,6) );
graphic->record( commandBuffer, descriptor, 0, metadata.type == uf::renderer::settings::pipelines::names::vxgi ? 0 : MIN(subpasses,6) );
}
}
#endif
for ( auto& pipeline : metadata.pipelines ) {
if ( pipeline == metadata.pipeline ) continue;
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getTarget() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass);
descriptor.pipeline = pipeline;
if ( pipeline == uf::renderer::settings::pipelines::names::culling ) {
descriptor.bind.width = graphic->descriptor.inputs.indirect.count;
descriptor.bind.height = 1;
descriptor.bind.depth = 1;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
} else if ( pipeline == uf::renderer::settings::pipelines::names::rt ) {
descriptor.bind.width = width;
descriptor.bind.height = height;
descriptor.bind.depth = 1;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
} else {
UF_MSG_DEBUG("Aux pipeline: {}", pipeline);
}
graphic->record( commandBuffer, descriptor, 0, metadata.type == uf::renderer::settings::pipelines::names::vxgi ? 0 : MIN(subpasses,6) );
}
}
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commands[i], 0, 1, &viewport);
vkCmdSetScissor(commands[i], 0, 1, &scissor);
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
for ( ; currentPass < subpasses; ++currentPass ) {
size_t currentDraw = 0;
for ( auto graphic : graphics ) {
if ( graphic->descriptor.renderMode != this->getTarget() ) continue;
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass);
graphic->record( commands[i], descriptor, currentPass, currentDraw++ );
graphic->record( commandBuffer, descriptor, currentPass, currentDraw++ );
}
if ( commandBufferCallbacks.count( currentPass ) > 0 ) commandBufferCallbacks[currentPass]( commands[i], i );
if ( currentPass + 1 < subpasses ) vkCmdNextSubpass(commands[i], VK_SUBPASS_CONTENTS_INLINE);
if ( commandBufferCallbacks.count( currentPass ) > 0 ) commandBufferCallbacks[currentPass]( commandBuffer, i );
if ( currentPass + 1 < subpasses ) vkCmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE);
}
vkCmdEndRenderPass(commands[i]);
vkCmdEndRenderPass(commandBuffer);
}
// post-renderpass commands
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i], i );
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commandBuffer, i );
}
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
}
}

View File

@ -25,6 +25,7 @@ namespace {
image = self->getAttachment(descriptor.name).image;
}
if ( image == VK_NULL_HANDLE ) continue;
subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, image, layout, descriptor.layout, subresourceRange );
}
}
@ -54,6 +55,7 @@ namespace {
image = self->getAttachment(descriptor.name).image;
}
if ( image == VK_NULL_HANDLE ) continue;
subresourceRange.aspectMask = descriptor.name == "depth" ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, image, descriptor.layout, layout, subresourceRange );
}
}

View File

@ -64,7 +64,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
if ( attachment->descriptor.mips == 0 ) {
attachment->descriptor.mips = 1;
} else {
attachment->descriptor.mips = static_cast<uint32_t>(std::floor(std::log2(std::max(width, height)))) + 1;
attachment->descriptor.mips = uf::vector::mips( pod::Vector2ui{ width, height } );
}
attachment->views.resize(this->views * attachment->descriptor.mips);

View File

@ -728,7 +728,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
size_t size = 4;
uint8_t buffer[size];
memset( &buffer[0], size, 0 );
memset( &buffer[0], 0, size );
auto& definition = metadata.definitions.specializationConstants[name];
definition.name = name;
@ -936,6 +936,26 @@ bool ext::vulkan::Shader::updateStorage( const uf::stl::string& name, const void
updateBuffer( data, size, getStorageBuffer(name) );
return true;
}
void ext::vulkan::Shader::setSpecializationConstants( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values ) {
uint32_t* specializationConstants = (uint32_t*) (void*) this->specializationConstants;
for ( auto pair : this->metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
if ( values.count(sc.name) == 0 ) continue;
sc.value.ui = (specializationConstants[sc.index] = values.at(sc.name));
}
}
void ext::vulkan::Shader::setDescriptorCounts( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values ) {
for ( auto pair : this->metadata.definitions.textures ) {
auto& tx = pair.second;
if ( values.count(tx.name) == 0 ) continue;
for ( auto& layout : this->descriptorSetLayoutBindings ) {
if ( layout.binding != tx.binding ) continue;
layout.descriptorCount = values.at(tx.name);
}
}
}
// JSON shit
#if 0 && UF_SHADER_PARSE_AS_JSON
uf::Serializer ext::vulkan::Shader::getUniformJson( const uf::stl::string& name, bool cache ) {

View File

@ -112,6 +112,14 @@ void ext::vulkan::Sampler::initialize( Device& device ) {
samplerCreateInfo.anisotropyEnable = descriptor.anisotropy.enabled;
samplerCreateInfo.maxAnisotropy = descriptor.anisotropy.max;
VkSamplerReductionModeCreateInfoEXT createInfoReduction{};
if ( descriptor.reduction.enabled ) {
createInfoReduction.sType = VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT;
createInfoReduction.reductionMode = descriptor.reduction.mode;
samplerCreateInfo.pNext = &createInfoReduction;
}
VK_CHECK_RESULT(vkCreateSampler(device.logicalDevice, &samplerCreateInfo, nullptr, &sampler));
}
{
@ -493,7 +501,7 @@ void ext::vulkan::Texture::fromBuffers(
// } else if ( this->depth == 1 ) {
} else {
// this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(texWidth, texHeight)))) + 1;
this->mips = static_cast<uint32_t>(std::floor(std::log2(std::max(std::max(texWidth, texHeight),texDepth)))) + 1;
this->mips = uf::vector::mips( pod::Vector3ui{ texWidth, texHeight, texDepth } );
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, &formatProperties);
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
@ -834,6 +842,15 @@ void ext::vulkan::Texture::generateMipmaps( VkCommandBuffer commandBuffer, uint3
}
bool isDepth = formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT;
switch ( format ) {
case ext::vulkan::enums::Format::D16_UNORM:
case ext::vulkan::enums::Format::D32_SFLOAT:
case ext::vulkan::enums::Format::D16_UNORM_S8_UINT:
case ext::vulkan::enums::Format::D24_UNORM_S8_UINT:
case ext::vulkan::enums::Format::D32_SFLOAT_S8_UINT:
isDepth = true;
break;
}
auto aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
auto filter = isDepth ? VK_FILTER_NEAREST : VK_FILTER_LINEAR;

View File

@ -15,8 +15,10 @@
#include <atomic>
namespace {
uf::stl::vector<VkFence> auxFencesGraphics;
uf::stl::vector<VkFence> auxFencesCompute;
struct {
uf::stl::vector<VkFence> graphics;
uf::stl::vector<VkFence> compute;
} auxFences;
}
uint32_t ext::vulkan::settings::width = 1280;
@ -335,15 +337,15 @@ void ext::vulkan::initialize() {
}
{
::auxFencesGraphics.resize( swapchain.buffers );
::auxFencesCompute.resize( swapchain.buffers );
::auxFences.graphics.resize( swapchain.buffers );
::auxFences.compute.resize( swapchain.buffers );
VkFenceCreateInfo fenceCreateInfo = {};
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
for ( auto& fence : ::auxFencesGraphics ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
for ( auto& fence : ::auxFencesCompute ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
for ( auto& fence : ::auxFences.graphics ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
for ( auto& fence : ::auxFences.compute ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
}
uf::graph::initialize();
@ -356,11 +358,8 @@ void ext::vulkan::initialize() {
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
tasks.queue([&]{
// auto guard = renderMode->guardMutex();
// renderMode->lockMutex();
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
renderMode->createCommandBuffers();
// renderMode->unlockMutex();
});
}
uf::thread::execute( tasks );
@ -381,7 +380,7 @@ void ext::vulkan::tick() {
#if 0
{
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread);
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
@ -397,7 +396,7 @@ void ext::vulkan::tick() {
#else
{
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
@ -442,11 +441,8 @@ void ext::vulkan::tick() {
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
if ( ext::vulkan::states::rebuild || renderMode->rebuild ) tasks.queue([&]{
// auto guard = renderMode->guardMutex();
// renderMode->lockMutex();
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
renderMode->createCommandBuffers();
// renderMode->unlockMutex();
});
}
uf::thread::execute( tasks );
@ -458,13 +454,14 @@ void ext::vulkan::tick() {
}
void ext::vulkan::render() {
if ( ext::vulkan::states::frameSkip ) {
// ext::vulkan::states::frameSkip = false;
ext::vulkan::states::frameSkip = false;
return;
}
ext::vulkan::mutex.lock();
// cleanup in-flight commands
for ( auto& pair : device.transient.commandBuffers ) {
auto transient = std::move(device.transient);
for ( auto& pair : /*device.*/transient.commandBuffers ) {
auto queueType = pair.first;
auto& commandBuffers = pair.second;
@ -495,63 +492,54 @@ void ext::vulkan::render() {
#endif
if ( settings::experimental::batchQueueSubmissions ) {
uf::stl::vector<VkFence> fences = { ::auxFences.compute[states::currentBuffer], ::auxFences.graphics[states::currentBuffer] };
uf::stl::vector<RenderMode*> auxRenderModes; auxRenderModes.reserve( renderModes.size() );
uf::stl::vector<RenderMode*> specialRenderModes; specialRenderModes.reserve( renderModes.size() );
for ( auto renderMode : renderModes ) {
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue;
// renderMode->lockMutex( renderMode->mostRecentCommandPoolId );
if ( renderMode->commandBufferCallbacks.count(RenderMode::EXECUTE_BEGIN) > 0 ) renderMode->commandBufferCallbacks[RenderMode::EXECUTE_BEGIN]( VkCommandBuffer{}, 0 );
if ( renderMode->getName() == "Gui" || renderMode->getName() == "" || renderMode->getName() == "Swapchain" )
specialRenderModes.emplace_back(renderMode);
else
auxRenderModes.emplace_back(renderMode);
if ( renderMode->getName() == "" || renderMode->getName() == "Swapchain" ) specialRenderModes.emplace_back(renderMode);
else auxRenderModes.emplace_back(renderMode);
}
uf::stl::vector<VkSubmitInfo> submitsGraphics; submitsGraphics.reserve( auxRenderModes.size() );
uf::stl::vector<VkSubmitInfo> submitsCompute; submitsCompute.reserve( auxRenderModes.size() );
// stuff we can batch
{
// Get next image in the swap chain (back/front buffer)
uf::stl::vector<VkSubmitInfo> submitsGraphics; submitsGraphics.reserve( auxRenderModes.size() );
uf::stl::vector<VkSubmitInfo> submitsCompute; submitsCompute.reserve( auxRenderModes.size() );
for ( auto renderMode : auxRenderModes ) {
auto submitInfo = renderMode->queue();
if ( submitInfo.sType != VK_STRUCTURE_TYPE_SUBMIT_INFO ) continue;
// auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
for ( auto renderMode : auxRenderModes ) {
auto submitInfo = renderMode->queue();
if ( submitInfo.sType != VK_STRUCTURE_TYPE_SUBMIT_INFO ) continue;
if ( renderMode->metadata.compute ) submitsCompute.emplace_back(submitInfo);
else submitsGraphics.emplace_back(submitInfo);
renderMode->executed = true;
// tasks.queue([&]{
ext::vulkan::setCurrentRenderMode(renderMode);
uf::graph::render();
uf::scene::render();
if ( renderMode->metadata.compute ) {
submitsCompute.emplace_back(submitInfo);
} else {
submitsGraphics.emplace_back(submitInfo);
}
renderMode->executed = true;
ext::vulkan::setCurrentRenderMode(NULL);
}
if ( !submitsCompute.empty() ) {
VK_CHECK_RESULT(vkWaitForFences(device, 1, &::auxFencesCompute[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
VK_CHECK_RESULT(vkResetFences(device, 1, &::auxFencesCompute[states::currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( QueueEnum::COMPUTE ), submitsCompute.size(), submitsCompute.data(), ::auxFencesCompute[states::currentBuffer]));
}
if ( !submitsGraphics.empty() ) {
VK_CHECK_RESULT(vkWaitForFences(device, 1, &::auxFencesGraphics[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
VK_CHECK_RESULT(vkResetFences(device, 1, &::auxFencesGraphics[states::currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( QueueEnum::GRAPHICS ), submitsGraphics.size(), submitsGraphics.data(), ::auxFencesGraphics[states::currentBuffer]));
}
// });
}
// uf::thread::execute( tasks );
VK_CHECK_RESULT(vkWaitForFences(device, fences.size(), fences.data(), VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
VK_CHECK_RESULT(vkResetFences(device, fences.size(), fences.data()));
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( QueueEnum::COMPUTE ), submitsCompute.size(), submitsCompute.data(), ::auxFences.compute[states::currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( QueueEnum::GRAPHICS ), submitsGraphics.size(), submitsGraphics.data(), ::auxFences.graphics[states::currentBuffer]));
// stuff we can't batch
{
for ( auto renderMode : specialRenderModes ) {
ext::vulkan::setCurrentRenderMode(renderMode);
uf::graph::render();
uf::scene::render();
renderMode->render();
ext::vulkan::setCurrentRenderMode(NULL);
}
for ( auto renderMode : specialRenderModes ) {
ext::vulkan::setCurrentRenderMode(renderMode);
uf::graph::render();
uf::scene::render();
renderMode->render();
ext::vulkan::setCurrentRenderMode(NULL);
}
#if UF_USE_FFX_FSR
if ( settings::pipelines::fsr ) {
ext::fsr::render();
@ -560,40 +548,29 @@ void ext::vulkan::render() {
for ( auto renderMode : renderModes ) {
if ( renderMode->commandBufferCallbacks.count(RenderMode::EXECUTE_END) > 0 ) renderMode->commandBufferCallbacks[RenderMode::EXECUTE_END]( VkCommandBuffer{}, 0 );
// renderMode->cleanupCommands( renderMode->mostRecentCommandPoolId );
// renderMode->unlockMutex( renderMode->mostRecentCommandPoolId );
}
} else {
for ( auto& renderMode : renderModes ) {
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue;
if ( renderMode->getName() == "Swapchain" ) {
#if UF_USE_FFX_FSR
if ( settings::pipelines::fsr ) {
ext::fsr::render();
}
#endif
}
#if UF_USE_FFX_FSR
if ( renderMode->getName() == "Swapchain" && settings::pipelines::fsr ) ext::fsr::render();
#endif
// renderMode->lockMutex( renderMode->mostRecentCommandPoolId );
// auto guard = renderMode->guardMutex( renderMode->mostRecentCommandPoolId );
ext::vulkan::setCurrentRenderMode(renderMode);
uf::graph::render();
uf::scene::render();
renderMode->render();
ext::vulkan::setCurrentRenderMode(NULL);
// renderMode->unlockMutex( renderMode->mostRecentCommandPoolId );
}
// for ( auto& renderMode : renderModes ) renderMode->cleanupCommands( renderMode->mostRecentCommandPoolId );
}
if ( ext::vulkan::settings::invariant::waitOnRenderEnd ) synchronize();
// if ( ext::openvr::context ) ext::openvr::postSubmit();
// cleanup in-flight buffers
for ( auto& buffer : device.transient.buffers ) buffer.destroy(false);
device.transient.buffers.clear();
for ( auto& buffer : transient.buffers ) buffer.destroy(false);
transient.buffers.clear();
ext::vulkan::mutex.unlock();
}
@ -619,8 +596,8 @@ void ext::vulkan::destroy() {
TextureCube::empty.destroy();
for ( auto& s : ext::vulkan::Sampler::samplers ) s.destroy();
for ( auto& fence : ::auxFencesGraphics ) vkDestroyFence( device, fence, nullptr);
for ( auto& fence : ::auxFencesCompute ) vkDestroyFence( device, fence, nullptr);
for ( auto& fence : ::auxFences.graphics ) vkDestroyFence( device, fence, nullptr);
for ( auto& fence : ::auxFences.compute ) vkDestroyFence( device, fence, nullptr);
ext::vulkan::scratchBuffer.destroy();

View File

@ -391,7 +391,7 @@ uf::Image uf::Image::replace(const Image::pixel_t& from, const Image::pixel_t& t
uf::Image uf::Image::subImage( const Image::vec2_t& start, const Image::vec2_t& end) const {
return *this;
/*
uf::Vector2ui size = parameter;
pod::Vector2ui size = parameter;
if ( mode == uf::Image::CropMode::START_SPAN_SIZE ) size = parameter;
if ( mode == uf::Image::CropMode::START_TO_END ) size = parameter - start;
if ( size > this->size ) return uf::Image(*this);

View File

@ -38,7 +38,7 @@ void UF_API uf::thread::tick( pod::Thread& thread ) {
while ( thread.running ) {
std::unique_lock<std::mutex> lock(*thread.mutex);
thread.conditions.queued.wait(lock, [&]{
return !thread.queue.empty() || !thread.running;
return (!thread.container.empty() || !thread.queue.empty()) || !thread.running;
});
uf::thread::process( thread );

View File

@ -106,13 +106,12 @@ void ext::BakingBehavior::initialize( uf::Object& self ) {
shader.buffers.insert( shader.buffers.begin(), metadata.buffers.uniforms.alias() );
});
// uf::thread::queue([&]{
uf::renderer::addRenderMode( &renderMode, metadata.renderModeName );
// });
uf::renderer::addRenderMode( &renderMode, metadata.renderModeName );
uf::renderer::states::rebuild = true;
UF_MSG_DEBUG("Finished initialiation.");
});
this->queueHook( "entity:PostInitialization.%UID%", 1.0f );
this->queueHook( "entity:PostInitialization.%UID%", 2.0f );
#endif
}
void ext::BakingBehavior::tick( uf::Object& self ) {

View File

@ -32,10 +32,10 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
auto& camera = this->getComponent<uf::Camera>();
auto& scene = uf::scene::getCurrentScene();
auto& controller = scene.getController();
auto& sceneMetadata = scene.getComponent<uf::Serializer>();
auto& sceneMetadataJson = scene.getComponent<uf::Serializer>();
if ( !sceneMetadata["system"]["lights"]["round robin hook bound"].as<bool>() ) {
sceneMetadata["system"]["lights"]["round robin hook bound"] = true;
if ( !sceneMetadataJson["system"]["lights"]["round robin hook bound"].as<bool>() ) {
sceneMetadataJson["system"]["lights"]["round robin hook bound"] = true;
scene.addHook("game:Frame.Start", [&]( ext::json::Value& payload ){
if ( ++::roundRobin.current >= ::roundRobin.lights.size() ) ::roundRobin.current = 0;
});
@ -56,8 +56,9 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
#if UF_USE_OPENGL
metadataJson["light"]["shadows"] = false;
#endif
if ( !sceneMetadata["light"]["shadows"]["enabled"].as<bool>(true) )
if ( !sceneMetadataJson["system"]["config"]["engine"]["scenes"]["lights"]["shadows"]["enabled"].as<bool>(true) ) {
metadataJson["light"]["shadows"] = false;
}
if ( metadataJson["light"]["shadows"].as<bool>() ) {
auto& cameraTransform = camera.getTransform();
cameraTransform.reference = &transform;

View File

@ -93,7 +93,7 @@ void ext::RayTraceSceneBehavior::tick( uf::Object& self ) {
static uf::stl::vector<uf::Graphic*> previousGraphics;
uf::stl::vector<uf::Graphic*> graphics;
auto& scene = uf::scene::getCurrentScene();
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
auto& graphic = entity->getComponent<uf::Graphic>();
@ -182,6 +182,21 @@ void ext::RayTraceSceneBehavior::tick( uf::Object& self ) {
shader.buffers.emplace_back( uf::graph::storage.buffers.texture.alias() );
shader.buffers.emplace_back( uf::graph::storage.buffers.light.alias() );
shader.setSpecializationConstants({
{ "TEXTURES", maxTextures2D },
{ "CUBEMAPS", maxTexturesCube },
{ "CASCADES", maxCascades },
});
shader.setDescriptorCounts({
{ "samplerTextures", maxTextures2D },
{ "samplerCubemaps", maxTexturesCube },
{ "voxelId", maxCascades },
{ "voxelUv", maxCascades },
{ "voxelNormal", maxCascades },
{ "voxelRadiance", maxCascades },
});
/*
uint32_t* specializationConstants = (uint32_t*) (void*) shader.specializationConstants;
for ( auto pair : shader.metadata.definitions.specializationConstants ) {
auto& sc = pair.second;
@ -201,7 +216,7 @@ void ext::RayTraceSceneBehavior::tick( uf::Object& self ) {
else if ( tx.name == "voxelRadiance" ) layout.descriptorCount = maxCascades;
}
}
*/
}
}
}

View File

@ -44,6 +44,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
auto& metadataJson = this->getComponent<uf::Serializer>();
this->addHook( "system:Quit.%UID%", [&](ext::json::Value& payload){
uf::renderer::settings::experimental::dedicatedThread = false;
ext::ready = false;
});
@ -355,7 +356,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
#endif
#if UF_USE_OPENGL
if ( metadata.light.enabled ) {
auto& graph = this->getGraph();
auto/*&*/ graph = this->getGraph();
auto& controller = this->getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& controllerMetadata = controller.getComponent<uf::Serializer>();
@ -420,7 +421,7 @@ void ext::ExtSceneBehavior::tick( uf::Object& self ) {
}
#elif UF_USE_VULKAN
{
auto& graph = this->getGraph();
auto/*&*/ graph = this->getGraph();
auto& controller = this->getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& controllerMetadata = controller.getComponent<uf::Serializer>();
@ -720,7 +721,7 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali
/*this->*/light.max = serializer["light"]["max"].as(/*this->*/light.max);
/*this->*/light.ambient = uf::vector::decode( serializer["light"]["ambient"], /*this->*/light.ambient);
if ( uf::renderer::settings::pipelines::fsr ) serializer["light"]["exposure"] = 1;
// if ( uf::renderer::settings::pipelines::fsr ) serializer["light"]["exposure"] = 1;
/*this->*/light.exposure = serializer["light"]["exposure"].as(/*this->*/light.exposure);
/*this->*/light.gamma = serializer["light"]["gamma"].as(/*this->*/light.gamma);
/*this->*/light.useLightmaps = serializer["light"]["useLightmaps"].as(/*this->*/light.useLightmaps);
@ -816,7 +817,7 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, const uf::stl::string
bindBuffers( self, *blitters.front(), shaderType, shaderPipeline );
}
void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic& graphic, const uf::stl::string& shaderType, const uf::stl::string& shaderPipeline ) {
auto& graph = this->getGraph();
auto/*&*/ graph = this->getGraph();
auto& controller = this->getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& controllerMetadata = controller.getComponent<uf::Serializer>();

View File

@ -201,7 +201,7 @@ void ext::VoxelizerSceneBehavior::tick( uf::Object& self ) {
metadata.extents.matrix = uf::matrix::orthographic( min.x, max.x, min.y, max.y, min.z, max.z );
auto& graph = scene.getGraph();
auto/*&*/ graph = scene.getGraph();
for ( auto entity : graph ) {
if ( !entity->hasComponent<uf::Graphic>() ) continue;
auto& graphic = entity->getComponent<uf::Graphic>();