Commit for 2020.09.20.7z

This commit is contained in:
mrq 2020-09-20 00:00:00 -05:00
parent e16ade7185
commit 177bc46065
27 changed files with 1210 additions and 517 deletions

View File

@ -0,0 +1,23 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
layout (binding = 1) uniform sampler samp;
layout (binding = 2) uniform texture2D albedoLeftTexture;
layout (binding = 3) uniform texture2D albedoRightTexture;
layout (location = 0) in vec2 inUv;
layout (location = 0) out vec4 outAlbedoSpecular;
layout( push_constant ) uniform PushBlock {
uint pass;
} PushConstant;
void main() {
if ( PushConstant.pass == 0 ) {
outAlbedoSpecular.rgb = texture(sampler2D(albedoLeftTexture, samp), inUv).rgb;
} else {
outAlbedoSpecular.rgb = texture(sampler2D(albedoRightTexture, samp), inUv).rgb;
}
outAlbedoSpecular.a = 1;
}

View File

@ -0,0 +1,16 @@
#version 450
layout (location = 0) in vec2 inPos;
layout (location = 1) in vec2 inUv;
layout (location = 0) out vec2 outUv;
out gl_PerVertex {
vec4 gl_Position;
};
void main() {
outUv = inUv;
gl_Position = vec4(inPos.xy, 0.0, 1.0);
}

View File

@ -17,9 +17,9 @@ layout (location = 0) out vec4 outFragColor;
struct Light {
vec3 position;
float power;
vec3 color;
float radius;
vec3 color;
float power;
int type;
int shadowed;
mat4 view;

View File

@ -1,408 +1,280 @@
#version 450
layout (local_size_x = 32, local_size_y = 32) in;
layout (binding = 0, rgba8) uniform writeonly image2D resultImage;
#define EPSILON 0.00001
layout (constant_id = 0) const uint LIGHTS = 16;
layout (constant_id = 1) const uint EYES = 2;
layout (binding = 0, rgba8) uniform writeonly image2D resultImage[EYES];
#define RAY_MARCH false
#define MARCH_STEPS 32
#define EPSILON 0.0001
#define MAXLEN 1000.0
#define SHADOW 0.5
#define RAYBOUNCES 4
#define REFLECTIONS true
#define REFLECTIONSTRENGTH 0.4
#define REFLECTIONFALLOFF 0.5
#define SHADOWS true
#define RAYBOUNCES 0
#define REFLECTION_STRENGTH 0.4
#define REFLECTION_FALLOFF 0.5
#define UINT32_MAX 0xFFFFFFFF
layout( push_constant ) uniform PushBlock {
uint pass;
} PushConstant;
#define TREE_SIZE 8
#define TREE_STACK 32
#define PRIMITIVE_TYPE_EMPTY UINT32_MAX
#define PRIMITIVE_TYPE_CUBE 1
#define PRIMITIVE_TYPE_LEAF 2
#define PRIMITIVE_TYPE_TREE 3
#define PRIMITIVE_TYPE_ROOT 4
struct Camera {
vec3 position;
mat4 view;
float aspectRatio;
struct Ray {
vec3 origin;
vec3 direction;
};
struct StartEnd {
uint start;
uint end;
struct Result {
vec3 color;
float t;
int id;
};
struct Cube {
vec4 position;
uint type;
// uint _padding[3];
};
struct Tree {
vec4 position;
uint type;
uint children[TREE_SIZE];
// uint _padding[3];
};
struct Light {
vec3 position;
float radius;
vec3 color;
float power;
vec2 type;
mat4 view;
mat4 projection;
};
layout (binding = 1) uniform UBO {
Camera camera;
StartEnd cubes;
StartEnd lights;
uint root;
struct State {
vec3 viewPosition;
Ray ray;
Result result;
} state;
layout (binding = 2) uniform UBO {
mat4 matrices[2];
vec4 ambient;
Light lights[LIGHTS];
} ubo;
layout (std140, binding = 2) buffer Cubes {
Cube cubes[ ];
};
layout (std430, binding = 3) buffer Trees {
Tree trees[ ];
};
layout (std140, binding = 4) buffer Lights {
Light lights[ ];
};
layout (binding = 5) uniform sampler2D samplerTexture;
// Lighting =========================================================
void reflectRay(inout vec3 rayD, in vec3 mormal) {
rayD = rayD + 2.0 * -dot(mormal, rayD) * mormal;
struct Shape {
vec4 values;
vec4 albedoSpecular;
int type;
};
layout (std140, binding = 3) buffer Shapes {
Shape shapes[];
};
void reflectRay(inout vec3 rayD, in vec3 normal) {
rayD = rayD + 2.0 * -dot(normal, rayD) * normal;
}
// Lighting =========================================================
float lightDiffuse(vec3 normal, vec3 lightDir) {
return clamp(dot(normal, lightDir), 0.1, 1.0);
}
float lightSpecular(vec3 normal, vec3 lightDir, float specularFactor) {
vec3 viewVec = normalize(ubo.camera.position);
vec3 viewVec = normalize(state.viewPosition);
vec3 halfVec = normalize(lightDir + viewVec);
return pow(clamp(dot(normal, halfVec), 0.0, 1.0), specularFactor);
}
// Cube ===========================================================
float cubeIntersect(vec3 rayO, vec3 rayD, vec3 rayDRecip, Cube cube) {
float t[10];
t[1] = ( cube.position.x - cube.position.w - rayO.x) * rayDRecip.x;
t[2] = ( cube.position.x + cube.position.w - rayO.x) * rayDRecip.x;
t[3] = ( cube.position.y - cube.position.w - rayO.y) * rayDRecip.y;
t[4] = ( cube.position.y + cube.position.w - rayO.y) * rayDRecip.y;
t[5] = ( cube.position.z - cube.position.w - rayO.z) * rayDRecip.z;
t[6] = ( cube.position.z + cube.position.w - rayO.z) * rayDRecip.z;
t[7] = max(max(min(t[1], t[2]), min(t[3], t[4])), min(t[5], t[6]));
t[8] = min(min(max(t[1], t[2]), max(t[3], t[4])), max(t[5], t[6]));
t[9] = (t[8] < 0 || t[7] > t[8]) ? 0.0 : t[7];
return t[9];
}
uint intersect(in vec3 rayO, in vec3 rayD, inout float resT, uint start, uint end) {
uint id = UINT32_MAX;
vec3 rayDRecip = 1.0f / rayD;
for (uint i = start; i < end && i < ubo.cubes.end && i < cubes.length(); i++) {
Cube cube = cubes[i];
if ( cube.type == PRIMITIVE_TYPE_EMPTY ) continue;
float tcube = cubeIntersect(rayO, rayD, rayDRecip, cube);
if ((tcube > EPSILON) && (tcube < resT)) {
id = i;
resT = tcube;
}
}
return id;
}
// Tree ===========================================================
float treeIntersect( in vec3 rayO, in vec3 rayD, in vec3 rayDRecip, Tree tree ) {
Cube treecube;
treecube.type = tree.type;
treecube.position = tree.position;
float t = cubeIntersect( rayO, rayD, rayDRecip, treecube );
// Sphere ===========================================================
float sphereIntersect(in vec3 rayO, in vec3 rayD, in Shape shape ) {
vec3 oc = rayO - shape.values.xyz;
float b = 2.0 * dot(oc, rayD);
float c = dot(oc, oc) - shape.values.w * shape.values.w;
float h = b*b - 4.0*c;
if (h < 0.0) return -1.0;
float t = (-b - sqrt(h)) / 2.0;
return t;
}
struct StackIterator {
uint tree;
uint child;
};
struct Stack {
int pointer;
StackIterator container[TREE_STACK];
};
Stack stack;
StackIterator popStack( ) {
StackIterator top = stack.container[stack.pointer];
stack.container[stack.pointer--] = StackIterator( UINT32_MAX, UINT32_MAX );
return top;
vec3 sphereNormal(in vec3 position, in Shape shape) {
return (position - shape.values.xyz) / shape.values.w;
}
void pushStack( StackIterator item ) {
stack.container[++stack.pointer] = item;
float sphereSDF( vec3 position, in Shape shape ) {
return length(position - shape.values.xyz) - shape.values.w;
}
uint intersectTreecursive( in vec3 rayO, in vec3 rayD, in vec3 rayDRecip, inout float resT, uint root ) {
uint id = UINT32_MAX;
if ( root == UINT32_MAX ) return id;
// set up stack
stack.pointer = -1;
for ( uint i = 0; i < TREE_STACK; ++i ) stack.container[i] = StackIterator( UINT32_MAX, UINT32_MAX );
pushStack(StackIterator( root, UINT32_MAX ));
while ( true ) {
StackIterator it = popStack();
// end of stack
if ( it.tree == UINT32_MAX ) break;
Tree tree = trees[it.tree];
// invalid tree
if ( tree.type == PRIMITIVE_TYPE_EMPTY ) break;
// new tree, parse collision
if ( it.child == UINT32_MAX ) {
float t = treeIntersect( rayO, rayD, rayDRecip, tree );
// bad intersection with this tree, continue with next iteration
if ( t <= EPSILON || t >= resT ) continue;
// push back with new stack
it.child = 0;
pushStack( it );
// continue with next iteration
continue;
} else if ( it.child >= TREE_SIZE ) {
// no new children, continue with next iteration
continue;
} else {
// is leaf
if ( tree.type == PRIMITIVE_TYPE_LEAF ) {
// check children for a match
for ( uint i = 0; i < TREE_SIZE; ++i ) {
uint branchId = tree.children[i];
// unallocated, skip
if ( branchId == UINT32_MAX ) continue;
Cube primitive = cubes[branchId];
if ( primitive.type == PRIMITIVE_TYPE_EMPTY ) continue;
float t = cubeIntersect( rayO, rayD, rayDRecip, primitive );
// branch intersects with ray, set as new parent
if ( (t <= EPSILON) || (t >= resT) ) continue;
id = branchId;
resT = t;
}
// continue with next iteration
continue;
}
// parse children
uint branchId = tree.children[it.child++];
// add new iterator to the stack
pushStack( it );
// unused child, continue with next iteration
if ( branchId == UINT32_MAX ) continue;
// tree branch, push to stack
// the first if block will check its collision
it.tree = branchId;
it.child = UINT32_MAX;
pushStack( it );
continue;
}
// Plane ===========================================================
float planeIntersect(in vec3 rayO, in vec3 rayD, in Shape shape) {
float d = dot(rayD, shape.values.xyz);
if (d == 0.0) return 0.0;
float t = -(shape.values.w + dot(rayO, shape.values.xyz)) / d;
return t < 0.0 ? 0.0 : t;
}
vec3 planeNormal(in vec3 position, in Shape shape) {
return shape.values.xyz;
}
float planeSDF( vec3 position, in Shape shape ) {
return dot( position, shape.values.xyz ) + shape.values.w;
}
// Generic =========================================================
float shapeIntersect(in vec3 rayO, in vec3 rayD, in Shape shape) {
if ( shape.type == 1 ) return sphereIntersect( rayO, rayD, shape );
if ( shape.type == 2 ) return planeIntersect( rayO, rayD, shape );
return 0.0;
}
vec3 shapeNormal( vec3 position, in Shape shape ) {
if ( shape.type == 1 ) return sphereNormal(position, shape);
if ( shape.type == 2 ) return planeNormal(position, shape);
return vec3(0.0);
}
float shapeSDF( vec3 position, in Shape shape ) {
if ( shape.type == 1 ) return sphereSDF(position, shape);
if ( shape.type == 2 ) return planeSDF(position, shape);
return MAXLEN;
}
// Intersect =======================================================
int intersect(in vec3 rayO, in vec3 rayD, inout float resT) {
int id = -1;
for (int i = 0; i < shapes.length(); i++) {
Shape shape = shapes[i];
float tShape = shapeIntersect(rayO, rayD, shape);
if ((tShape > EPSILON) && (tShape < resT)) {
id = i;
resT = tShape;
}
}
return id;
}
uint intersectTree( in vec3 rayO, in vec3 rayD, in vec3 rayDRecip, inout float resT ) {
uint id = UINT32_MAX;
// traverse the tree branches to the leaf
uint index = 0;
while ( true ) {
Tree tree = trees[index++];
if ( tree.type == PRIMITIVE_TYPE_EMPTY ) break;
if ( tree.type != PRIMITIVE_TYPE_LEAF ) continue;
float tcube = treeIntersect( rayO, rayD, rayDRecip, tree );
// ray fails collision with parent tree
if ( (tcube <= EPSILON) || (tcube >= resT) ) continue;
// ray intersects with parent tree, check children branches
for ( uint i = 0; i < TREE_SIZE; ++i ) {
uint branchId = tree.children[i];
// unallocated, skip
if ( branchId == UINT32_MAX ) continue;
Cube primitive = cubes[branchId];
if ( primitive.type == PRIMITIVE_TYPE_EMPTY ) continue;
tcube = cubeIntersect( rayO, rayD, rayDRecip, primitive );
// branch intersects with ray, set as new parent
if ( (tcube <= EPSILON) || (tcube >= resT) ) continue;
id = branchId;
resT = tcube;
}
}
return id;
}
float calcShadow(in vec3 rayO, in vec3 rayD, in uint objectId, inout float t, uint start, uint end) {
vec3 rayDRecip = 1.0f / rayD;
for (uint i = ubo.cubes.start; i < ubo.cubes.end && i < cubes.length(); i++) {
if (i == objectId) continue;
float tCube = cubeIntersect(rayO, rayD, rayDRecip, cubes[i]);
if ((tCube > EPSILON) && (tCube < t)) {
t = tCube;
float calcShadow(in vec3 rayO, in vec3 rayD, in int objectID, inout float resT) {
for (int i = 0; i < shapes.length(); i++) {
if ( i == objectID ) continue;
Shape shape = shapes[i];
float tShape = shapeIntersect(rayO, rayD, shape);
if ((tShape > EPSILON) && (tShape < resT)) {
resT = tShape;
return SHADOW;
}
}
}
return 1.0;
}
float calcShadowTree(in vec3 rayO, in vec3 rayD, in vec3 rayDRecip, in uint objectId, inout float t){
// traverse the tree branches to the leaf
uint index = 0;
while ( true ) {
Tree tree = trees[index++];
if ( tree.type == PRIMITIVE_TYPE_EMPTY ) break;
if ( tree.type != PRIMITIVE_TYPE_LEAF ) continue;
float tcube = treeIntersect( rayO, rayD, rayDRecip, tree );
// ray fails collision with parent tree
if ( (tcube <= EPSILON) || (tcube >= t) ) continue;
// ray intersects with parent tree, check children branches
for ( uint i = 0; i < TREE_SIZE; ++i ) {
uint branchId = tree.children[i];
// unallocated, skip
if ( branchId == UINT32_MAX ) continue;
Cube primitive = cubes[branchId];
if ( primitive.type == PRIMITIVE_TYPE_EMPTY ) continue;
if ( branchId == objectId ) continue;
tcube = cubeIntersect( rayO, rayD, rayDRecip, primitive );
// branch intersects with ray, set as new parent
if ( (tcube <= EPSILON) || (tcube >= t) ) continue;
t = tcube;
// Marching ========================================
int intersectMarch( in vec3 rayO, in vec3 rayD, inout float resT ) {
resT = 0;
for (int i = 0; i < MARCH_STEPS; ++i) {
vec3 position = resT * rayD + rayO;
float tNearest = MAXLEN;
int objectID = -1;
for ( int j = 0; j < shapes.length(); ++j ) {
Shape shape = shapes[j];
float tShape = shapeSDF(position, shape);
// if ((tShape > EPSILON) && (tShape < tNearest)) {
if ( tShape < tNearest ) {
objectID = j;
tNearest = tShape;
}
}
if (tNearest < EPSILON) {
return objectID;
}
if (resT > MAXLEN) break;
resT += tNearest;
}
resT = MAXLEN;
return -1;
}
float calcShadowMarch( in vec3 rayO, in vec3 rayD, in int objectID, inout float resT ) {
float distance = resT;
resT = 0;
for (int i = 0; i < MARCH_STEPS; ++i) {
vec3 position = resT * rayD + rayO;
float tNearest = distance;
int objectID = -1;
for ( int j = 0; j < shapes.length(); ++j ) {
if ( j == objectID ) continue;
Shape shape = shapes[j];
float tShape = shapeSDF(position, shape);
// if ((tShape > EPSILON) && (tShape < tNearest)) {
if ( tShape < tNearest ) {
objectID = j;
tNearest = tShape;
}
}
if (tNearest < EPSILON) {
return SHADOW;
}
if (resT > distance) break;
resT += tNearest;
}
resT = distance;
return 1.0;
}
vec3 fog(in float t, in vec3 color) {
return mix(color, vec3(0, 0, 0), clamp(sqrt(t*t)/20.0, 0.0, 1.0));
vec3 fogColor = vec3(0.1);
return mix(color, fogColor.rgb, clamp(sqrt(t*t)/20.0, 0.0, 1.0));
}
vec3 renderScene(inout vec3 rayO, inout vec3 rayD, inout uint id) {
float t = MAXLEN;
vec3 rayDRecip = 1.0f / rayD;
// Get intersected object ID
uint objectID = intersect(rayO, rayD, t, ubo.cubes.start, ubo.cubes.end );
// uint objectID = intersectTree( rayO, rayD, rayDRecip, t );
// uint objectID = intersectTreecursive( rayO, rayD, rayDRecip, t, ubo.root );
vec3 color = vec3(0.0);
if ( objectID == UINT32_MAX ) return color;
Result renderScene(inout vec3 rayO, inout vec3 rayD ) {
Result result;
result.color = vec3(0.0);
result.t = MAXLEN;
result.id = RAY_MARCH ? intersectMarch(rayO, rayD, result.t) : intersect(rayO, rayD, result.t);
if (result.id == -1) return result;
vec3 pos = rayO + t * rayD;
vec3 normal;
Shape shape = shapes[result.id];
vec3 position = rayO + result.t * rayD;
vec3 normal = shapeNormal( position, shape );
// Cubes
if ( id == UINT32_MAX ) return color;
id = objectID;
// Hit Data
{
Cube cube = cubes[objectID];
vec2 mappedUv = vec2(0, 0); {
float min_distance = MAXLEN;
vec3 point = cube.position.xyz - pos;
float distance = abs(cube.position.w - abs(point.x));
if (distance < min_distance) {
min_distance = distance;
normal = vec3(-1, 0, 0);
if ( cube.position.w + point.x <= EPSILON ) normal *= -1;
for ( uint i = 0; i < LIGHTS; ++i ) {
Light light = ubo.lights[i];
if ( light.radius <= EPSILON ) continue;
if ( light.power <= EPSILON ) continue;
mappedUv.x = point.y - cube.position.y;
mappedUv.y = point.z - cube.position.z;
}
distance = abs(cube.position.w - abs(point.y));
if (distance < min_distance) {
min_distance = distance;
normal = vec3(0, -1, 0);
if ( cube.position.w + point.y <= EPSILON ) normal *= -1;
vec3 L = light.position - position;
float dist = length(L);
vec3 D = normalize(L);
float attenuation = light.radius / (pow(dist, 2.0) + 1.0);;
attenuation = 1;
// if ( dist > light.radius ) continue;
vec4 albedoSpecular = shape.albedoSpecular;
mappedUv.x = point.x - cube.position.x;
mappedUv.y = point.z - cube.position.z;
}
distance = abs(cube.position.w - abs(point.z));
if (distance < min_distance) {
min_distance = distance;
normal = vec3(0, 0, -1);
if ( cube.position.w + point.z <= EPSILON ) normal *= -1;
float d_dot = lightDiffuse(normal, D);
float s_factor = lightSpecular(normal, D, albedoSpecular.a);
vec3 color = (light.color * albedoSpecular.rgb) * d_dot + s_factor;
mappedUv.x = point.x - cube.position.x;
mappedUv.y = point.y - cube.position.y;
}
mappedUv -= 2.0f / 4.0f;
mappedUv *= 1.0f / 4.0f;
mappedUv.x = mod(mappedUv.x, 1.0f / 4.0f);
mappedUv.y = mod(mappedUv.y, 1.0f / 4.0f);
}
vec3 textureMapped = texture(samplerTexture, mappedUv).rgb;
color = textureMapped;
}
// Lighting
{
int di = 0;
vec4 diffuses[256];
for ( int j = 0; j < lights.length(); ++j ) {
Light light = lights[j];
if ( light.color.r <= EPSILON && light.color.g <= EPSILON && light.color.b <= EPSILON ) continue;
vec3 lightVec = normalize(light.position - pos);
float diffuse = lightDiffuse(normal, lightVec);
float specular = lightSpecular(normal, lightVec, 2000.0f);
diffuses[di].x = length(light.position - pos);
diffuses[di].gba = diffuse * light.color + specular;
++di;
}
vec4 a = vec4(MAXLEN, vec3(1.0));
vec4 b = vec4(MAXLEN, vec3(1.0));
vec4 c = vec4(MAXLEN, vec3(1.0));
for ( int j = 0; j < lights.length(); ++j ) {
vec4 current = diffuses[j];
if ( current.y <= EPSILON ) continue;
// use slot a
if ( current.x < a.x ) {
c = b;
b = a;
a = current;
} else if ( current.x < b.x ) {
c = b;
b = current;
} else if ( current.x < c.x ) {
c = current;
}
}
vec3 avg = (a.gba * 0.5 + b.gba * 0.3 + c.gba * 0.2);
color *= avg;
}
// Shadows
{
vec3 lightVec = vec3(0, 4, 0) - pos;
t = length(lightVec);
color *= calcShadow(pos, lightVec, id, t, ubo.cubes.start, ubo.cubes.end);
// color *= calcShadowTree(pos, lightVec, rayDRecip, id, t);
// Shadows
float tShadow = dist;
float shadowed = 1;
if ( SHADOWS )
shadowed = RAY_MARCH ? calcShadowMarch(position, D, result.id, tShadow) : calcShadow(position, D, result.id, tShadow);
result.color += color * light.power * attenuation * shadowed;
}
// Fog
// color = fog(t, color);
// result.color = fog(t, result.color);
// Reflect ray for next render pass
reflectRay(rayD, normal);
rayO = pos;
rayO = position;
return color;
return result;
}
void main() {
ivec2 dim = imageSize(resultImage);
vec2 uv = vec2(gl_GlobalInvocationID.xy) / dim;
for ( int pass = 0; pass < EYES; ++pass ) {
{
vec2 uv = vec2(gl_GlobalInvocationID.xy) / imageSize(resultImage[pass]);
vec4 near4 = ubo.matrices[pass] * (vec4(2.0 * uv - 1.0, -1.0, 1.0));
vec4 far4 = ubo.matrices[pass] * (vec4(2.0 * uv - 1.0, 1.0, 1.0));
vec3 near3 = near4.xyz / near4.w;
vec3 far3 = far4.xyz / far4.w;
vec3 rayO = ubo.camera.position; // * vec3(1,1,-1);
vec3 rayD = normalize(vec3((-1.0 + 2.0 * uv) * vec2(ubo.camera.aspectRatio, 1.0), -1.0));
rayD = (ubo.camera.view * vec4( rayD, 0.0 )).xyz;
// Basic color path
uint id = 0;
vec3 finalColor = renderScene(rayO, rayD, id);
// Reflection
if ( REFLECTIONS ) {
float reflectionStrength = REFLECTIONSTRENGTH;
for (int i = 0; i < RAYBOUNCES; i++) {
vec3 reflectionColor = renderScene(rayO, rayD, id);
finalColor = (1.0 - reflectionStrength) * finalColor + reflectionStrength * mix(reflectionColor, finalColor, 1.0 - reflectionStrength);
reflectionStrength *= REFLECTIONFALLOFF;
state.viewPosition = near3;
state.ray.origin = near3;
state.ray.direction = normalize( far3 - near3 );
}
// Basic color path
state.result = renderScene(state.ray.origin, state.ray.direction);
vec3 finalColor = state.result.color;
// Reflection
float reflectionStrength = REFLECTION_STRENGTH;
for (int i = 0; i < RAYBOUNCES; i++) {
Result result = renderScene(state.ray.origin, state.ray.direction);
vec3 reflectionColor = result.color;
finalColor = (1.0 - reflectionStrength) * finalColor + reflectionStrength * mix(reflectionColor, finalColor, 1.0 - reflectionStrength);
reflectionStrength *= REFLECTION_FALLOFF;
}
imageStore(resultImage[pass], ivec2(gl_GlobalInvocationID.xy), vec4(finalColor, 1.0));
}
imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(finalColor, 0.0));
}

View File

@ -5,7 +5,7 @@ layout (location = 0) in vec2 inUV;
layout (location = 0) out vec4 outFragColor;
void main() {
vec4 sampledColor = texture(samplerColor, vec2(inUV.s, 1.0 - inUV.t));
vec4 sampledColor = texture(samplerColor, inUV);
if ( sampledColor.r <= 0.000001 && sampledColor.g <= 0.000001 && sampledColor.b <= 0.000001 ) discard;
outFragColor = sampledColor;
}

View File

@ -12,21 +12,33 @@ namespace ext {
VkSurfaceKHR surface;
VkPhysicalDevice physicalDevice;
VkDevice logicalDevice;
VkCommandPool commandPool = VK_NULL_HANDLE;
struct {
VkCommandPool graphics = VK_NULL_HANDLE;
VkCommandPool compute = VK_NULL_HANDLE;
VkCommandPool transfer = VK_NULL_HANDLE;
} commandPool;
VkPhysicalDeviceProperties properties;
VkPhysicalDeviceFeatures features;
VkPhysicalDeviceFeatures enabledFeatures;
VkPhysicalDeviceMemoryProperties memoryProperties;
VkPhysicalDeviceProperties2 properties2;
VkPhysicalDeviceFeatures2 features2;
VkPhysicalDeviceFeatures2 enabledFeatures2;
VkPhysicalDeviceMemoryProperties2 memoryProperties2;
VkPipelineCache pipelineCache;
std::vector<VkQueueFamilyProperties> queueFamilyProperties;
std::vector<std::string> supportedExtensions;
VkQueue graphicsQueue;
VkQueue presentQueue;
VkQueue computeQueue;
struct {
VkQueue graphics;
VkQueue present;
VkQueue compute;
VkQueue transfer;
} queues;
uf::Window* window;
@ -41,7 +53,6 @@ namespace ext {
uint32_t present;
uint32_t compute;
uint32_t transfer;
} queueFamilyIndices;
operator VkDevice() { return this->logicalDevice; };
@ -51,7 +62,7 @@ namespace ext {
int rate( VkPhysicalDevice device );
VkCommandBuffer createCommandBuffer( VkCommandBufferLevel level, bool begin = false );
void flushCommandBuffer( VkCommandBuffer commandBuffer, VkQueue queue, bool free = true );
void flushCommandBuffer( VkCommandBuffer commandBuffer, bool free = true );
VkResult createBuffer(
VkBufferUsageFlags usageFlags,

View File

@ -32,6 +32,7 @@ namespace ext {
virtual void render();
virtual void destroy();
virtual void synchronize( uint64_t = UINT64_MAX );
virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 );
};
}
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <uf/ext/vulkan/rendermode.h>
#include <uf/ext/vulkan/graphic.h>
namespace ext {
namespace vulkan {
struct UF_API ComputeRenderMode : public ext::vulkan::RenderMode {
ext::vulkan::Graphic blitter, compute;
pod::Vector2ui dispatchSize = { 32, 32 };
// RAII
virtual std::string getType() const;
virtual void createCommandBuffers();
virtual void initialize( Device& device );
virtual void tick();
virtual void render();
virtual void destroy();
virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 );
};
}
}

View File

@ -20,6 +20,7 @@ namespace ext {
virtual void tick();
virtual void destroy();
virtual void render();
virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 );
};
}
}

View File

@ -89,7 +89,6 @@ namespace ext {
void loadFromFile(
std::string filename,
Device& device,
VkQueue copyQueue,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
@ -98,7 +97,6 @@ namespace ext {
void loadFromImage(
uf::Image& image,
Device& device,
VkQueue copyQueue,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
@ -118,7 +116,6 @@ namespace ext {
uint32_t texWidth,
uint32_t texHeight,
Device& device,
VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT,
VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
);
@ -126,7 +123,6 @@ namespace ext {
Device& device,
uint32_t texWidth,
uint32_t texHeight,
VkQueue copyQueue,
VkFormat format = VK_FORMAT_R8G8B8A8_UNORM
);
void aliasAttachment( const RenderTarget::Attachment& attachment, bool = true );

View File

@ -45,6 +45,8 @@ namespace ext {
extern UF_API bool validation;
extern UF_API std::vector<std::string> validationFilters;
extern UF_API std::vector<std::string> requestedDeviceFeatures;
extern UF_API std::vector<std::string> requestedDeviceExtensions;
extern UF_API std::vector<std::string> requestedInstanceExtensions;
extern UF_API Device device;
typedef VmaAllocator Allocator;
extern UF_API Allocator allocator;
@ -60,9 +62,11 @@ namespace ext {
extern UF_API std::vector<RenderMode*> renderModes;
extern UF_API std::vector<uf::Scene*> scenes;
bool UF_API hasRenderMode( const std::string&, bool = true );
RenderMode& UF_API addRenderMode( RenderMode*, const std::string& = "" );
RenderMode& UF_API getRenderMode( const std::string&, bool = true );
std::vector<RenderMode*> UF_API getRenderModes( const std::string&, bool = true );
std::vector<RenderMode*> UF_API getRenderModes( const std::vector<std::string>&, bool = true );
void UF_API removeRenderMode( RenderMode*, bool = true );
void UF_API initialize( uint8_t = 0 );

View File

@ -5,6 +5,7 @@
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/rendermodes/compute.h>
#include <uf/ext/vulkan/rendermodes/stereoscopic_deferred.h>
UF_OBJECT_REGISTER_CPP(Scene)
@ -25,7 +26,16 @@ void uf::Scene::tick() {
std::vector<ext::vulkan::Graphic*> blitters;
auto& renderMode = ext::vulkan::getRenderMode("", true);
if ( renderMode.getType() == "Deferred (Stereoscopic)" ) {
bool hasCompute = ext::vulkan::hasRenderMode("C:RT:" + std::to_string(this->getUid()), true);
if ( hasCompute ) {
// auto& renderMode = ext::vulkan::getRenderMode("C:RT:" + std::to_string(this->getUid()), true);
// auto* renderModePointer = (ext::vulkan::ComputeRenderMode*) &renderMode;
// if ( renderModePointer->compute.initialized ) {
// blitters.push_back(&renderModePointer->compute);
// } else {
// hasCompute = false;
// }
} else if ( renderMode.getType() == "Deferred (Stereoscopic)" ) {
auto* renderModePointer = (ext::vulkan::StereoscopicDeferredRenderMode*) &renderMode;
blitters.push_back(&renderModePointer->blitters.left);
blitters.push_back(&renderModePointer->blitters.right);
@ -134,18 +144,18 @@ void uf::Scene::tick() {
if ( entity == &controller ) light.position.y += 2;
light.position.w = metadata["light"]["power"].asFloat();
light.position.w = metadata["light"]["radius"].asFloat();
light.color.x = metadata["light"]["color"][0].asFloat();
light.color.y = metadata["light"]["color"][1].asFloat();
light.color.z = metadata["light"]["color"][2].asFloat();
light.color.w = metadata["light"]["radius"].asFloat();
light.color.w = metadata["light"]["power"].asFloat();
light.type.x = metadata["light"]["type"].asUInt64();
light.type.y = metadata["light"]["shadows"]["enabled"].asBool();
if ( entity->hasComponent<ext::vulkan::RenderTargetRenderMode>() ) {
if ( !hasCompute && entity->hasComponent<ext::vulkan::RenderTargetRenderMode>() ) {
auto& renderMode = entity->getComponent<ext::vulkan::RenderTargetRenderMode>();
auto& renderTarget = renderMode.renderTarget;

View File

@ -288,7 +288,7 @@ void ext::openvr::tick() {
graphic.initializeGeometry(mesh);
auto& texture = graphic.material.textures.emplace_back();
texture.fromBuffers( (void*) queued.texture->rubTextureMapData, len, VK_FORMAT_R8G8B8A8_UNORM, queued.texture->unWidth, queued.texture->unHeight, ext::vulkan::device, ext::vulkan::device.graphicsQueue );
texture.fromBuffers( (void*) queued.texture->rubTextureMapData, len, VK_FORMAT_R8G8B8A8_UNORM, queued.texture->unWidth, queued.texture->unHeight, ext::vulkan::device );
}
// clear
{
@ -455,7 +455,7 @@ void ext::openvr::submit() { bool invert = swapEyes;
vulkanData.m_pDevice = ( VkDevice_T * ) ext::vulkan::device;
vulkanData.m_pPhysicalDevice = ( VkPhysicalDevice_T * ) ext::vulkan::device.physicalDevice;
vulkanData.m_pInstance = ( VkInstance_T *) ext::vulkan::device.instance;
vulkanData.m_pQueue = ( VkQueue_T * ) ext::vulkan::device.presentQueue;
vulkanData.m_pQueue = ( VkQueue_T * ) ext::vulkan::device.queues.present;
vulkanData.m_nQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
vulkanData.m_nWidth = width;

View File

@ -176,7 +176,7 @@ size_t ext::vulkan::Buffers::initializeBuffer( void* data, VkDeviceSize length,
return index;
}
VkQueue queue = device->graphicsQueue;
// VkQueue queue = device->queues.transfer;
Buffer staging;
VkDeviceSize storageBufferSize = length;
device->createBuffer(
@ -199,7 +199,7 @@ size_t ext::vulkan::Buffers::initializeBuffer( void* data, VkDeviceSize length,
VkBufferCopy copyRegion = {};
copyRegion.size = storageBufferSize;
vkCmdCopyBuffer(copyCmd, staging.buffer, buffer.buffer, 1, &copyRegion);
device->flushCommandBuffer(copyCmd, queue, true);
device->flushCommandBuffer(copyCmd, true);
staging.destroy();
// buffers.push_back( std::move(buffer) );
@ -225,7 +225,7 @@ void ext::vulkan::Buffers::updateBuffer( void* data, VkDeviceSize length, Buffer
buffer.unmap();
return;
}
VkQueue queue = device->graphicsQueue;
// VkQueue queue = device->queues.transfer;
Buffer staging;
device->createBuffer(
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
@ -240,6 +240,6 @@ void ext::vulkan::Buffers::updateBuffer( void* data, VkDeviceSize length, Buffer
VkBufferCopy copyRegion = {};
copyRegion.size = length;
vkCmdCopyBuffer(copyCmd, staging.buffer, buffer.buffer, 1, &copyRegion);
device->flushCommandBuffer(copyCmd, queue, true);
device->flushCommandBuffer(copyCmd, true);
staging.destroy();
}

View File

@ -258,7 +258,7 @@ int ext::vulkan::Device::rate( VkPhysicalDevice device ) {
}
VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel level, bool begin ){
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( commandPool, level, 1 );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( commandPool.transfer, level, 1 );
VkCommandBuffer commandBuffer;
VK_CHECK_RESULT( vkAllocateCommandBuffers( logicalDevice, &cmdBufAllocateInfo, &commandBuffer ) );
@ -270,7 +270,7 @@ VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel l
return commandBuffer;
}
void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, VkQueue queue, bool free ) {
void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, bool free ) {
if ( commandBuffer == VK_NULL_HANDLE ) return;
VK_CHECK_RESULT( vkEndCommandBuffer( commandBuffer ) );
@ -285,13 +285,13 @@ void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, VkQ
VK_CHECK_RESULT(vkCreateFence(logicalDevice, &fenceInfo, nullptr, &fence));
// Submit to the queue
VK_CHECK_RESULT(vkQueueSubmit(queue, 1, &submitInfo, fence));
VK_CHECK_RESULT(vkQueueSubmit(device.queues.transfer, 1, &submitInfo, fence));
// Wait for the fence to signal that command buffer has finished executing
VK_CHECK_RESULT(vkWaitForFences(logicalDevice, 1, &fence, VK_TRUE, DEFAULT_FENCE_TIMEOUT));
vkDestroyFence(logicalDevice, fence, nullptr);
if ( free ) vkFreeCommandBuffers(logicalDevice, commandPool, 1, &commandBuffer);
if ( free ) vkFreeCommandBuffers(logicalDevice, commandPool.transfer, 1, &commandBuffer);
}
VkResult ext::vulkan::Device::createBuffer( VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer* buffer, VkDeviceMemory* memory, void *data ) {
@ -406,8 +406,10 @@ void ext::vulkan::Device::initialize() {
}
//
// Get extensions
// OpenVR Support
std::vector<std::string> requestedExtensions = window->getExtensions( ext::vulkan::validation );
// Load any requested extensions
requestedExtensions.insert( requestedExtensions.end(), ext::vulkan::requestedInstanceExtensions.begin(), ext::vulkan::requestedInstanceExtensions.end() );
// OpenVR Support
if ( ext::openvr::enabled ) VRExtensions(requestedExtensions);
{
@ -508,11 +510,20 @@ void ext::vulkan::Device::initialize() {
}
// Update properties
{
vkGetPhysicalDeviceProperties( this->physicalDevice, &properties );
// Features should be checked by the examples before using them
vkGetPhysicalDeviceFeatures( this->physicalDevice, &features );
// Memory properties are used regularly for creating all kinds of buffers
vkGetPhysicalDeviceMemoryProperties( this->physicalDevice, &memoryProperties );
{
vkGetPhysicalDeviceProperties( this->physicalDevice, &properties );
// Features should be checked by the examples before using them
vkGetPhysicalDeviceFeatures( this->physicalDevice, &features );
// Memory properties are used regularly for creating all kinds of buffers
vkGetPhysicalDeviceMemoryProperties( this->physicalDevice, &memoryProperties );
}
{
vkGetPhysicalDeviceProperties2( this->physicalDevice, &properties2 );
// Features should be checked by the examples before using them
vkGetPhysicalDeviceFeatures2( this->physicalDevice, &features2 );
// Memory properties are used regularly for creating all kinds of buffers
vkGetPhysicalDeviceMemoryProperties2( this->physicalDevice, &memoryProperties2 );
}
// Queue family properties, used for setting up requested queues upon device creation
uint32_t queueFamilyCount;
vkGetPhysicalDeviceQueueFamilyProperties( this->physicalDevice, &queueFamilyCount, nullptr );
@ -524,43 +535,45 @@ void ext::vulkan::Device::initialize() {
{
bool useSwapChain = true;
VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
std::vector<std::string> requestedExtensions;
std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
requestedExtensions.insert( requestedExtensions.end(), ext::vulkan::requestedInstanceExtensions.begin(), ext::vulkan::requestedInstanceExtensions.end() );
/* OpenVR support */ if ( ext::openvr::enabled && vr::VRCompositor() ) {
uint32_t nBufferSize = vr::VRCompositor()->GetVulkanDeviceExtensionsRequired( ( VkPhysicalDevice_T * ) this->physicalDevice, nullptr, 0 );
if ( nBufferSize > 0 ) {
char pExtensionStr[nBufferSize];
pExtensionStr[0] = 0;
vr::VRCompositor()->GetVulkanDeviceExtensionsRequired( ( VkPhysicalDevice_T * ) this->physicalDevice, pExtensionStr, nBufferSize );
std::vector<std::string> extensions = uf::string::split( pExtensionStr, " " );
// Allocate enough ExtensionProperties to support all extensions being enabled
uint32_t extensionsCount = 0;
uint32_t enabledExtensionsCount = 0;
VK_CHECK_RESULT(vkEnumerateDeviceExtensionProperties( this->physicalDevice, NULL, &extensionsCount, NULL ));
std::vector<VkExtensionProperties> extensionProperties(extensionsCount);
VK_CHECK_RESULT( vkEnumerateDeviceExtensionProperties( this->physicalDevice, NULL, &extensionsCount, &extensionProperties[0] ) );
for ( size_t i = 0; i < extensions.size(); ++i ) {
bool found = false;
uint32_t index = 0;
for ( index = 0; index < extensionsCount; index++ ) {
if ( strcmp( extensions[i].c_str(), extensionProperties[index].extensionName ) == 0 ) {
for ( auto alreadyAdded : deviceExtensions ) {
if ( strcmp( extensions[i].c_str(), alreadyAdded ) == 0 ) {
found = true;
break;
}
std::vector<std::string> vrExtensions = uf::string::split( pExtensionStr, " " );
requestedExtensions.insert( requestedExtensions.end(), vrExtensions.begin(), vrExtensions.end() );
}
// Allocate enough ExtensionProperties to support all extensions being enabled
uint32_t extensionsCount = 0;
uint32_t enabledExtensionsCount = 0;
VK_CHECK_RESULT(vkEnumerateDeviceExtensionProperties( this->physicalDevice, NULL, &extensionsCount, NULL ));
std::vector<VkExtensionProperties> extensionProperties(extensionsCount);
VK_CHECK_RESULT( vkEnumerateDeviceExtensionProperties( this->physicalDevice, NULL, &extensionsCount, &extensionProperties[0] ) );
for ( size_t i = 0; i < requestedExtensions.size(); ++i ) {
bool found = false;
uint32_t index = 0;
for ( index = 0; index < extensionsCount; index++ ) {
if ( strcmp( requestedExtensions[i].c_str(), extensionProperties[index].extensionName ) == 0 ) {
for ( auto alreadyAdded : deviceExtensions ) {
if ( strcmp( requestedExtensions[i].c_str(), alreadyAdded ) == 0 ) {
found = true;
break;
}
if ( found ) break;
found = true;
deviceExtensions.push_back(extensionProperties[index].extensionName);
}
if ( found ) break;
found = true;
deviceExtensions.push_back(extensionProperties[index].extensionName);
}
if ( !found ) std::cout << "Vulkan missing requested extension " << extensions[index] << std::endl;
}
if ( !found ) std::cout << "Vulkan missing requested extension " << requestedExtensions[index] << std::endl;
}
}
@ -648,8 +661,26 @@ void ext::vulkan::Device::initialize() {
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndices.graphics;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool!");
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool.graphics ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for graphics!");
}
{
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndices.compute;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool.compute ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for compute!");
}
{
VkCommandPoolCreateFlags createFlags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPoolCreateInfo cmdPoolInfo = {};
cmdPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cmdPoolInfo.queueFamilyIndex = queueFamilyIndices.transfer;
cmdPoolInfo.flags = createFlags;
if ( vkCreateCommandPool( this->logicalDevice, &cmdPoolInfo, nullptr, &commandPool.transfer ) != VK_SUCCESS )
throw std::runtime_error("failed to create command pool for transfer!");
}
// Set queue
{
@ -681,9 +712,10 @@ void ext::vulkan::Device::initialize() {
device.queueFamilyIndices.present = presentQueueNodeIndex;
vkGetDeviceQueue( device, device.queueFamilyIndices.graphics, 0, &graphicsQueue );
vkGetDeviceQueue( device, device.queueFamilyIndices.present, 0, &presentQueue );
vkGetDeviceQueue( device, device.queueFamilyIndices.compute, 0, &computeQueue );
vkGetDeviceQueue( device, device.queueFamilyIndices.graphics, 0, &queues.graphics );
vkGetDeviceQueue( device, device.queueFamilyIndices.present, 0, &queues.present );
vkGetDeviceQueue( device, device.queueFamilyIndices.compute, 0, &queues.compute );
vkGetDeviceQueue( device, device.queueFamilyIndices.transfer, 0, &queues.transfer );
}
// Set formats
{
@ -750,9 +782,17 @@ void ext::vulkan::Device::destroy() {
vkDestroyPipelineCache( this->logicalDevice, this->pipelineCache, nullptr );
this->pipelineCache = nullptr;
}
if ( this->commandPool ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool, nullptr );
this->commandPool = nullptr;
if ( this->commandPool.graphics ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool.graphics, nullptr );
this->commandPool.graphics = nullptr;
}
if ( this->commandPool.compute ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool.compute, nullptr );
this->commandPool.compute = nullptr;
}
if ( this->commandPool.transfer ) {
vkDestroyCommandPool( this->logicalDevice, this->commandPool.transfer, nullptr );
this->commandPool.transfer = nullptr;
}
if ( this->logicalDevice ) {
vkDestroyDevice( this->logicalDevice, nullptr );

View File

@ -61,10 +61,17 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st
auto parseResource = [&]( const spirv_cross::Resource& resource, VkDescriptorType descriptorType ) {
switch ( descriptorType ) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
const auto& base_type = comp.get_type(resource.base_type_id);
auto& uniform = uniforms.emplace_back();
const auto& base_type = comp.get_type(resource.base_type_id);
uniform.create( comp.get_declared_struct_size(base_type) );
} break;
/*
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
auto& uniform = uniforms.emplace_back();
// const auto& base_type = comp.get_type(resource.base_type_id);
// uniform.create( comp.get_declared_struct_size(base_type) );
} break;
*/
}
const auto& type = comp.get_type(resource.type_id);
@ -73,8 +80,9 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const std::st
descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, comp.get_decoration(resource.id, spv::DecorationBinding), size ) );
};
// std::cout << "Found resource: "#type " with binding: " << comp.get_decoration(resource.id, spv::DecorationBinding) << std::endl;\
// std::cout << "["<<filename<<"] Found resource: "#type " with binding: " << comp.get_decoration(resource.id, spv::DecorationBinding) << std::endl;\
#define LOOP_RESOURCES( key, type ) for ( const auto& resource : res.key ) {\
parseResource( resource, type );\
}
@ -257,6 +265,21 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
}
// Compute
for ( auto& shader : graphic.material.shaders ) {
if ( shader.descriptor.stage != VK_SHADER_STAGE_COMPUTE_BIT ) continue;
// Create compute shader pipelines
VkComputePipelineCreateInfo computePipelineCreateInfo = ext::vulkan::initializers::computePipelineCreateInfo(
pipelineLayout,
0
);
computePipelineCreateInfo.stage = shader.descriptor;
VK_CHECK_RESULT(vkCreateComputePipelines(device, device.pipelineCache, 1, &computePipelineCreateInfo, nullptr, &pipeline));
return;
}
// Graphic
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = ext::vulkan::initializers::pipelineInputAssemblyStateCreateInfo(
graphic.descriptor.topology,
@ -272,30 +295,42 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
rasterizationState.lineWidth = graphic.descriptor.lineWidth;
std::vector<VkPipelineColorBlendAttachmentState> blendAttachmentStates;
auto& subpass = renderTarget.passes[graphic.descriptor.subpass];
/*
for ( auto& color : subpass.colors ) {
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
0xf,
VK_TRUE
);
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
blendAttachmentStates.push_back(blendAttachmentState);
}
*/
for ( auto& color : subpass.colors ) {
blendAttachmentStates.push_back(renderTarget.attachments[color.attachment].blendState);
}
// require blending if independentBlend is not an enabled feature
if ( !device.enabledFeatures.independentBlend ) {
for ( size_t i = 1; i < blendAttachmentStates.size(); ++i ) {
blendAttachmentStates[i] = blendAttachmentStates[0];
if ( renderMode.getType() != "Swapchain" ) {
auto& subpass = renderTarget.passes[graphic.descriptor.subpass];
for ( auto& color : subpass.colors ) {
blendAttachmentStates.push_back(renderTarget.attachments[color.attachment].blendState);
}
// require blending if independentBlend is not an enabled feature
if ( !device.enabledFeatures.independentBlend ) {
for ( size_t i = 1; i < blendAttachmentStates.size(); ++i ) {
blendAttachmentStates[i] = blendAttachmentStates[0];
}
}
} else {
graphic.descriptor.subpass = 0;
VkBool32 blendEnabled = VK_FALSE;
VkColorComponentFlags writeMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT;
if ( true ) {
blendEnabled = VK_TRUE;
writeMask |= VK_COLOR_COMPONENT_A_BIT;
}
VkPipelineColorBlendAttachmentState blendAttachmentState = ext::vulkan::initializers::pipelineColorBlendAttachmentState(
writeMask,
blendEnabled
);
if ( blendEnabled == VK_TRUE ) {
blendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
blendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD;
blendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
blendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
blendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD;
}
blendAttachmentStates.push_back(blendAttachmentState);
}
VkPipelineColorBlendStateCreateInfo colorBlendState = ext::vulkan::initializers::pipelineColorBlendStateCreateInfo(
@ -377,7 +412,11 @@ void ext::vulkan::Pipeline::initialize( Graphic& graphic ) {
}
}
void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuffer ) {
auto bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
for ( auto& shader : graphic.material.shaders ) {
if ( shader.descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) {
bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
}
size_t offset = 0;
for ( auto& pushConstant : shader.pushConstants ) {
struct PushConstant {
@ -395,10 +434,10 @@ void ext::vulkan::Pipeline::record( Graphic& graphic, VkCommandBuffer commandBuf
}
}
// Bind descriptor sets describing shader binding points
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
// Bind the rendering pipeline
// The pipeline (state object) contains all states of the rendering pipeline, binding it will set all the states specified at pipeline creation time
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindPipeline(commandBuffer, bindPoint, pipeline);
}
void ext::vulkan::Pipeline::update( Graphic& graphic ) {
// generate fallback empty texture
@ -416,19 +455,22 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
RenderMode& renderMode = ext::vulkan::getRenderMode(graphic.descriptor.renderMode, true);
auto& renderTarget = renderMode.getRenderTarget(graphic.descriptor.renderTarget );
auto& subpass = renderTarget.passes[graphic.descriptor.subpass];
for ( auto& input : subpass.inputs ) {
inputDescriptors.push_back(ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[input.attachment].view,
// input.layout
input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout
));
if ( graphic.descriptor.subpass < renderTarget.passes.size() ) {
auto& subpass = renderTarget.passes[graphic.descriptor.subpass];
for ( auto& input : subpass.inputs ) {
inputDescriptors.push_back(ext::vulkan::initializers::descriptorImageInfo(
renderTarget.attachments[input.attachment].view,
// input.layout
input.layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL : input.layout
));
}
}
{
for ( auto& shader : graphic.material.shaders ) {
auto textures = graphic.material.textures.begin();
auto samplers = graphic.material.samplers.begin();
auto buffers = shader.buffers.begin();
auto buffersUniforms = shader.buffers.begin();
auto buffersStorage = graphic.buffers.begin();
auto attachments = inputDescriptors.begin();
for ( auto& layout : shader.descriptorSetLayoutBindings ) {
@ -436,7 +478,8 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
if ( layout.descriptorCount > 1 ) {
switch ( layout.descriptorType ) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
size_t imageInfosStart = imageInfos.size();
// assume we have a texture, and fill it in the slots as defaults
for ( size_t i = 0; i < layout.descriptorCount; ++i ) {
@ -467,7 +510,8 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
VkDescriptorImageInfo* imageInfo = NULL;
switch ( layout.descriptorType ) {
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE: {
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE: {
if ( textures == graphic.material.textures.end() ) {
imageInfo = &emptyTexture.descriptor;
break;
@ -482,15 +526,27 @@ void ext::vulkan::Pipeline::update( Graphic& graphic ) {
imageInfo = &((samplers++)->descriptor.info);
} break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
if ( buffers == shader.buffers.end() ) {
std::cout << "buffers == shader.buffers.end()" << std::endl;
if ( buffersUniforms == shader.buffers.end() ) {
std::cout << "buffersUniforms == shader.buffers.end()" << std::endl;
break;
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&((buffers++)->descriptor)
&((buffersUniforms++)->descriptor)
));
} break;
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
if ( buffersStorage == graphic.buffers.end() ) {
std::cout << "buffersStorage == graphic.buffers.end()" << std::endl;
break;
}
writeDescriptorSets.push_back(ext::vulkan::initializers::writeDescriptorSet(
descriptorSet,
layout.descriptorType,
layout.binding,
&((buffersStorage++)->descriptor)
));
} break;
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT: {

View File

@ -49,7 +49,8 @@ void ext::vulkan::RenderMode::createCommandBuffers() {
scene->process(filter);
}
VK_CHECK_RESULT(vkWaitForFences(*device, fences.size(), fences.data(), VK_TRUE, UINT64_MAX));
this->synchronize();
//VK_CHECK_RESULT(vkWaitForFences(*device, fences.size(), fences.data(), VK_TRUE, UINT64_MAX));
createCommandBuffers( graphics );
}
void ext::vulkan::RenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics ) {
@ -77,13 +78,13 @@ void ext::vulkan::RenderMode::render() {
submitInfo.commandBufferCount = 1;
// Submit to the graphics queue passing a wait fence
VK_CHECK_RESULT(vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, fences[currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]));
// Present the current buffer to the swap chain
// Pass the semaphore signaled by the command buffer submission from the submit info as the wait semaphore for swap chain presentation
// This ensures that the image is not presented to the windowing system until all commands have been submitted
VK_CHECK_RESULT(swapchain.queuePresent(device->presentQueue, currentBuffer, renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device->presentQueue));
VK_CHECK_RESULT(swapchain.queuePresent(device->queues.present, currentBuffer, renderCompleteSemaphore));
VK_CHECK_RESULT(vkQueueWaitIdle(device->queues.present));
}
void ext::vulkan::RenderMode::initialize( Device& device ) {
@ -101,7 +102,7 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
commands.resize( swapchain.buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
device.commandPool,
this->getType() == "Compute" ? device.commandPool.compute : device.commandPool.graphics,
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(commands.size())
);
@ -147,7 +148,7 @@ void ext::vulkan::RenderMode::destroy() {
renderTarget.destroy();
if ( commands.size() > 0 ) {
vkFreeCommandBuffers( *device, device->commandPool, static_cast<uint32_t>(commands.size()), commands.data());
vkFreeCommandBuffers( *device, this->getType() == "Compute" ? device->commandPool.compute : device->commandPool.graphics, static_cast<uint32_t>(commands.size()), commands.data());
}
if ( renderCompleteSemaphore != VK_NULL_HANDLE ) {
@ -162,4 +163,6 @@ void ext::vulkan::RenderMode::destroy() {
void ext::vulkan::RenderMode::synchronize( uint64_t timeout ) {
if ( !device ) return;
VK_CHECK_RESULT(vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, timeout ));
}
void ext::vulkan::RenderMode::pipelineBarrier( VkCommandBuffer command, uint8_t stage ) {
}

View File

@ -0,0 +1,211 @@
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/compute.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/initializers.h>
#include <uf/ext/openvr/openvr.h>
#include <uf/utils/window/window.h>
#include <uf/utils/graphic/graphic.h>
#include <uf/ext/vulkan/graphic.h>
#include <uf/engine/scene/scene.h>
#include <uf/utils/camera/camera.h>
#include <uf/utils/math/transform.h>
#include <uf/ext/vulkan/graphic.h>
std::string ext::vulkan::ComputeRenderMode::getType() const {
return "Compute";
}
void ext::vulkan::ComputeRenderMode::initialize( Device& device ) {
ext::vulkan::RenderMode::initialize( device );
// this->width = 3840;
// this->height = 2160;
{
auto width = this->width > 0 ? this->width : ext::vulkan::width;
auto height = this->height > 0 ? this->height : ext::vulkan::height;
compute.device = &device;
compute.material.device = &device;
compute.descriptor.renderMode = this->name;
compute.material.initializeShaders({
{"./data/shaders/raytracing.comp.spv", VK_SHADER_STAGE_COMPUTE_BIT},
});
for ( size_t i = 0; i < (ext::openvr::context ? 2 : 1); ++i ) {
Texture2D& texture = compute.material.textures.emplace_back();
texture.asRenderTarget( device, width, height );
}
{
auto& scene = uf::scene::getCurrentScene();
auto& metadata = scene.getComponent<uf::Serializer>();
auto& shader = compute.material.shaders.front();
struct SpecializationConstant {
int32_t eyes = 2;
int32_t maxLights = 16;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
specializationConstants.eyes = ext::openvr::context ? 2 : 1;
}
// update buffers
if ( !compute.buffers.empty() ) {
auto& pipeline = compute.getPipeline();
pipeline.update( compute );
}
}
{
uf::BaseMesh<pod::Vertex_2F2F, uint32_t> mesh;
mesh.vertices = {
{ {-1.0f, 1.0f}, {0.0f, 1.0f}, },
{ {-1.0f, -1.0f}, {0.0f, 0.0f}, },
{ {1.0f, -1.0f}, {1.0f, 0.0f}, },
{ {1.0f, 1.0f}, {1.0f, 1.0f}, }
};
mesh.indices = {
0, 1, 2, 2, 3, 0
};
blitter.device = &device;
blitter.material.device = &device;
blitter.descriptor.subpass = 1;
blitter.descriptor.depthTest.test = false;
blitter.descriptor.depthTest.write = false;
blitter.initializeGeometry( mesh );
blitter.material.initializeShaders({
{"./data/shaders/display.blit.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.blit.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
for ( auto& computeTexture : compute.material.textures ) {
Texture2D& texture = blitter.material.textures.emplace_back();
texture = computeTexture;
texture.device = NULL;
}
blitter.initializePipeline();
}
}
void ext::vulkan::ComputeRenderMode::render() {
if ( compute.buffers.empty() ) return;
// Submit compute commands
// Use a fence to ensure that compute command buffer has finished executing before using it again
VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[currentBuffer], VK_TRUE, UINT64_MAX ));
VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[currentBuffer] ));
VkSubmitInfo submitInfo = ext::vulkan::initializers::submitInfo();
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commands[currentBuffer];
VK_CHECK_RESULT(vkQueueSubmit(device->queues.compute, 1, &submitInfo, fences[currentBuffer]));
}
void ext::vulkan::ComputeRenderMode::tick() {
ext::vulkan::RenderMode::tick();
if ( ext::vulkan::resized ) {
// auto-resize texture
if ( this->width == 0 && this->height == 0 ) {
auto width = this->width > 0 ? this->width : ext::vulkan::width;
auto height = this->height > 0 ? this->height : ext::vulkan::height;
for ( auto& texture : compute.material.textures ) {
texture.destroy();
}
compute.material.textures.clear();
for ( size_t i = 0; i < (ext::openvr::context ? 2 : 1); ++i ) {
Texture2D& texture = compute.material.textures.emplace_back();
texture.asRenderTarget( *device, width, height );
}
}
// update blitter descriptor set
if ( blitter.initialized ) {
blitter.material.textures.clear();
for ( auto& computeTexture : compute.material.textures ) {
Texture2D& texture = blitter.material.textures.emplace_back();
texture = computeTexture;
texture.device = NULL;
}
auto& pipeline = blitter.getPipeline();
pipeline.update( blitter );
}
// if ( compute.initialized ) {
if ( !compute.buffers.empty() ) {
auto& pipeline = compute.getPipeline();
pipeline.update( compute );
}
}
}
void ext::vulkan::ComputeRenderMode::destroy() {
ext::vulkan::RenderMode::destroy();
blitter.destroy();
compute.destroy();
}
void ext::vulkan::ComputeRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) {
if ( compute.buffers.empty() ) return;
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
for ( auto& texture : compute.material.textures ) {
VkPipelineStageFlags srcStageMask, dstStageMask;
imageMemoryBarrier.image = texture.image;
imageMemoryBarrier.oldLayout = texture.descriptor.imageLayout;
imageMemoryBarrier.newLayout = texture.descriptor.imageLayout;
switch ( state ) {
case 0: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
srcStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} break;
case 1: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageMask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
} break;
// ensure
default: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
}
}
vkCmdPipelineBarrier( commandBuffer,
srcStageMask, dstStageMask,
VK_FLAGS_NONE,
0, NULL,
0, NULL,
1, &imageMemoryBarrier
);
texture.descriptor.imageLayout = imageMemoryBarrier.newLayout;
}
}
void ext::vulkan::ComputeRenderMode::createCommandBuffers( ) {
this->synchronize();
float width = this->width > 0 ? this->width : ext::vulkan::width;
float height = this->height > 0 ? this->height : ext::vulkan::height;
if ( compute.buffers.empty() ) return;
VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo();
auto& pipeline = compute.getPipeline();
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
pipeline.record(compute, commands[i]);
vkCmdDispatch(commands[i], width / dispatchSize.x, height / dispatchSize.y, 1);
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
}
}

View File

@ -100,6 +100,17 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
{"./data/shaders/display.subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
{
auto& scene = uf::scene::getCurrentScene();
auto& metadata = scene.getComponent<uf::Serializer>();
auto& shader = blitter.material.shaders.back();
struct SpecializationConstant {
int32_t maxLights = 16;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
}
blitter.initializePipeline();
}
}
@ -128,7 +139,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = nullptr;
/*
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
@ -137,8 +148,9 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
std::vector<RenderMode*> layers = ext::vulkan::getRenderModes("RenderTarget", false);
*/
std::vector<RenderMode*> layers = ext::vulkan::getRenderModes(std::vector<std::string>{"RenderTarget", "Compute"}, false);
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
@ -182,8 +194,9 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
scissor.offset.y = 0;
// transition layers for read
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 0 );
/*
if ( layer->getName() == "" ) continue;
RenderTarget& renderTarget = layer->renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
@ -197,6 +210,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}
*/
}
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
@ -234,6 +248,8 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
vkCmdEndRenderPass(commands[i]);
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 1 );
/*
if ( layer->getName() == "" ) continue;
RenderTarget& renderTarget = layer->renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
@ -247,6 +263,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const std::vector<ex
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}
*/
}
}

View File

@ -93,6 +93,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
{"./data/shaders/display.renderTarget.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.renderTarget.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
@ -144,7 +145,7 @@ void ext::vulkan::RenderTargetRenderMode::render() {
submitInfo.pCommandBuffers = &commands[currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.commandBufferCount = 1;
VK_CHECK_RESULT(vkQueueSubmit(device->graphicsQueue, 1, &submitInfo, fences[currentBuffer]));
VK_CHECK_RESULT(vkQueueSubmit(device->queues.graphics, 1, &submitInfo, fences[currentBuffer]));
/*
VkSemaphoreWaitInfo waitInfo = {};
waitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO;
@ -155,6 +156,60 @@ void ext::vulkan::RenderTargetRenderMode::render() {
VK_CHECK_RESULT(vkWaitSemaphores( *device, &waitInfo, UINT64_MAX ));
*/
}
void ext::vulkan::RenderTargetRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) {
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
for ( auto& attachment : renderTarget.attachments ) {
if ( !(attachment.usage & VK_IMAGE_USAGE_SAMPLED_BIT) ) continue;
if ( (attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) ) continue;
VkPipelineStageFlags srcStageMask, dstStageMask;
imageMemoryBarrier.image = attachment.image;
imageMemoryBarrier.oldLayout = attachment.layout;
imageMemoryBarrier.newLayout = attachment.layout;
switch ( state ) {
case 0: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
} break;
case 1: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.newLayout = attachment.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
} break;
// ensure
default: {
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
dstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
}
}
vkCmdPipelineBarrier( commandBuffer,
srcStageMask, dstStageMask,
VK_FLAGS_NONE,
0, NULL,
0, NULL,
1, &imageMemoryBarrier
);
attachment.layout = imageMemoryBarrier.newLayout;
}
}
void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const std::vector<ext::vulkan::Graphic*>& graphics ) {
// destroy if exists
float width = this->width > 0 ? this->width : ext::vulkan::width;

View File

@ -116,6 +116,17 @@ void ext::vulkan::StereoscopicDeferredRenderMode::initialize( Device& device ) {
{"./data/shaders/display.subpass.vert.spv", VK_SHADER_STAGE_VERTEX_BIT},
{"./data/shaders/display.subpass.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT}
});
{
auto& scene = uf::scene::getCurrentScene();
auto& metadata = scene.getComponent<uf::Serializer>();
auto& shader = blitter.material.shaders.back();
struct SpecializationConstant {
int32_t maxLights = 16;
};
auto& specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
specializationConstants.maxLights = metadata["system"]["config"]["engine"]["scenes"]["max lights"].asUInt64();
}
blitter.initializePipeline();
}
}
@ -169,7 +180,7 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
std::vector<RenderMode*> layers = ext::vulkan::getRenderModes("RenderTarget", false);
std::vector<RenderMode*> layers = ext::vulkan::getRenderModes(std::vector<std::string>{"RenderTarget", "Compute"}, false);
for (size_t i = 0; i < commands.size(); ++i) {
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
@ -225,6 +236,8 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
// transition layers for read
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 0 );
/*
if ( layer->getName() == "" ) continue;
RenderTarget& renderTarget = layer->renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
@ -238,6 +251,7 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}
*/
}
vkCmdBeginRenderPass(commands[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
@ -275,6 +289,8 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
vkCmdEndRenderPass(commands[i]);
for ( auto layer : layers ) {
layer->pipelineBarrier( commands[i], 1 );
/*
if ( layer->getName() == "" ) continue;
RenderTarget& renderTarget = layer->renderTarget;
for ( auto& attachment : renderTarget.attachments ) {
@ -288,6 +304,7 @@ void ext::vulkan::StereoscopicDeferredRenderMode::createCommandBuffers( const st
vkCmdPipelineBarrier( commands[i], VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT , 0, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
attachment.layout = imageMemoryBarrier.newLayout;
}
*/
}
}
// Blit eye to swapchain

View File

@ -198,12 +198,11 @@ void ext::vulkan::Texture2D::loadFromFile(
VkImageLayout imageLayout,
bool forceLinear
) {
return loadFromFile( filename, ext::vulkan::device, ext::vulkan::device.graphicsQueue, format, imageUsageFlags, imageLayout, forceLinear );
return loadFromFile( filename, ext::vulkan::device, format, imageUsageFlags, imageLayout, forceLinear );
}
void ext::vulkan::Texture2D::loadFromFile(
std::string filename,
Device& device,
VkQueue copyQueue,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
@ -274,7 +273,6 @@ void ext::vulkan::Texture2D::loadFromFile(
image.getDimensions()[0],
image.getDimensions()[1],
device,
copyQueue,
imageUsageFlags,
imageLayout
);
@ -286,12 +284,11 @@ void ext::vulkan::Texture2D::loadFromImage(
VkImageLayout imageLayout,
bool forceLinear
) {
return loadFromImage( image, ext::vulkan::device, ext::vulkan::device.graphicsQueue, format, imageUsageFlags, imageLayout, forceLinear );
return loadFromImage( image, ext::vulkan::device, format, imageUsageFlags, imageLayout, forceLinear );
}
void ext::vulkan::Texture2D::loadFromImage(
uf::Image& image,
Device& device,
VkQueue copyQueue,
VkFormat format,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout,
@ -346,7 +343,6 @@ void ext::vulkan::Texture2D::loadFromImage(
image.getDimensions()[0],
image.getDimensions()[1],
device,
copyQueue,
imageUsageFlags,
imageLayout
);
@ -358,14 +354,12 @@ void ext::vulkan::Texture2D::fromBuffers(
uint32_t texWidth,
uint32_t texHeight,
Device& device,
VkQueue copyQueue,
VkImageUsageFlags imageUsageFlags,
VkImageLayout imageLayout
) {
this->initialize(device, texWidth, texHeight);
this->mips = 1;
// Use a separate command buffer for texture loading
VkCommandBuffer copyCmd = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
@ -455,7 +449,7 @@ void ext::vulkan::Texture2D::fromBuffers(
imageLayout,
subresourceRange
);
device.flushCommandBuffer(copyCmd, copyQueue);
device.flushCommandBuffer(copyCmd);
// Clean up staging resources
/*
vkFreeMemory(device.logicalDevice, staging.memory, nullptr);
@ -481,10 +475,10 @@ void ext::vulkan::Texture2D::fromBuffers(
this->updateDescriptors();
}
void ext::vulkan::Texture2D::asRenderTarget( Device& device, uint32_t width, uint32_t height, VkQueue copyQueue, VkFormat format ) {
void ext::vulkan::Texture2D::asRenderTarget( Device& device, uint32_t width, uint32_t height, VkFormat format ) {
// Prepare blit target texture
this->initialize( device, width, height );
// Get device properties for the requested texture format
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, &formatProperties);
@ -530,7 +524,7 @@ void ext::vulkan::Texture2D::asRenderTarget( Device& device, uint32_t width, uin
imageLayout
);
device.flushCommandBuffer(layoutCmd, copyQueue, true);
device.flushCommandBuffer(layoutCmd, true);
// Create sampler
sampler.initialize( device );

View File

@ -14,6 +14,8 @@ uint32_t ext::vulkan::height = 720;
bool ext::vulkan::validation = true;
std::vector<std::string> ext::vulkan::validationFilters;
std::vector<std::string> ext::vulkan::requestedDeviceFeatures;
std::vector<std::string> ext::vulkan::requestedDeviceExtensions;
std::vector<std::string> ext::vulkan::requestedInstanceExtensions;
ext::vulkan::Device ext::vulkan::device;
ext::vulkan::Allocator ext::vulkan::allocator;
ext::vulkan::Swapchain ext::vulkan::swapchain;
@ -159,17 +161,15 @@ void ext::vulkan::alignedFree(void* data) {
#endif
}
namespace {
bool hasRenderMode( const std::string& name, bool isName ) {
for ( auto& renderMode: ext::vulkan::renderModes ) {
if ( isName ) {
if ( renderMode->getName() == name ) return true;
} else {
if ( renderMode->getType() == name ) return true;
}
bool ext::vulkan::hasRenderMode( const std::string& name, bool isName ) {
for ( auto& renderMode: ext::vulkan::renderModes ) {
if ( isName ) {
if ( renderMode->getName() == name ) return true;
} else {
if ( renderMode->getType() == name ) return true;
}
return false;
}
return false;
}
ext::vulkan::RenderMode& ext::vulkan::addRenderMode( ext::vulkan::RenderMode* mode, const std::string& name ) {
@ -180,7 +180,7 @@ ext::vulkan::RenderMode& ext::vulkan::addRenderMode( ext::vulkan::RenderMode* mo
return *mode;
}
ext::vulkan::RenderMode& ext::vulkan::getRenderMode( const std::string& name, bool isName ) {
RenderMode* target = renderModes[renderModes.size()-1];
RenderMode* target = renderModes[0];
for ( auto& renderMode: renderModes ) {
if ( isName ) {
if ( renderMode->getName() == "" ) target = renderMode;
@ -199,9 +199,12 @@ ext::vulkan::RenderMode& ext::vulkan::getRenderMode( const std::string& name, bo
return *target;
}
std::vector<ext::vulkan::RenderMode*> ext::vulkan::getRenderModes( const std::string& name, bool isName ) {
return ext::vulkan::getRenderModes({name}, isName);
}
std::vector<ext::vulkan::RenderMode*> ext::vulkan::getRenderModes( const std::vector<std::string>& names, bool isName ) {
std::vector<RenderMode*> targets;
for ( auto& renderMode: renderModes ) {
if ( ( isName && renderMode->getName() == name ) || renderMode->getType() == name ) {
if ( ( isName && std::find(names.begin(), names.end(), renderMode->getName()) != names.end() ) || std::find(names.begin(), names.end(), renderMode->getType()) != names.end() ) {
targets.push_back(renderMode);
// std::cout << "Requestings RenderMode `" << name << "`, got `" << renderMode->getName() << "` (" << renderMode->getType() << ")" << std::endl;
}
@ -233,7 +236,7 @@ void ext::vulkan::initialize( uint8_t stage ) {
};
Texture2D::empty.sampler.descriptor.filter.min = VK_FILTER_NEAREST;
Texture2D::empty.sampler.descriptor.filter.mag = VK_FILTER_NEAREST;
Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), VK_FORMAT_R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, ext::vulkan::device.graphicsQueue, VK_IMAGE_USAGE_SAMPLED_BIT );
Texture2D::empty.fromBuffers( (void*) &pixels[0], pixels.size(), VK_FORMAT_R8G8B8A8_UNORM, 2, 2, ext::vulkan::device, VK_IMAGE_USAGE_SAMPLED_BIT );
}
for ( auto& renderMode : renderModes ) {
if ( !renderMode ) continue;
@ -303,6 +306,11 @@ void ext::vulkan::tick() {
}
void ext::vulkan::render() {
// ext::vulkan::mutex.lock();
if ( hasRenderMode("Gui", true) ) {
RenderMode& primary = getRenderMode("Gui", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );
if ( it + 1 != renderModes.end() ) std::rotate( it, it + 1, renderModes.end() );
}
if ( hasRenderMode("", true) ) {
RenderMode& primary = getRenderMode("", true);
auto it = std::find( renderModes.begin(), renderModes.end(), &primary );

View File

@ -37,6 +37,7 @@
#include <uf/engine/asset/asset.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/compute.h>
#include <uf/ext/vulkan/rendermodes/stereoscopic_deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/discord/discord.h>
@ -107,26 +108,35 @@ void EXT_API ext::initialize() {
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["validation"]["filters"].size(); ++i ) {
ext::vulkan::validationFilters.push_back( ::config["engine"]["ext"]["vulkan"]["validation"]["filters"][i].asString() );
}
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["extensions"]["device"].size(); ++i ) {
ext::vulkan::requestedDeviceExtensions.push_back( ::config["engine"]["ext"]["vulkan"]["extensions"]["device"][i].asString() );
}
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["extensions"]["instance"].size(); ++i ) {
ext::vulkan::requestedInstanceExtensions.push_back( ::config["engine"]["ext"]["vulkan"]["extensions"]["instance"][i].asString() );
}
for ( int i = 0; i < ::config["engine"]["ext"]["vulkan"]["features"].size(); ++i ) {
ext::vulkan::requestedDeviceFeatures.push_back( ::config["engine"]["ext"]["vulkan"]["features"][i].asString() );
}
//
// ext::vulkan::DeferredRenderingGraphic::maxLights = ::config["engine"]["scenes"]["max lights"].asUInt();
//
ext::openvr::enabled = ::config["engine"]["ext"]["vr"]["enable"].asBool();
ext::openvr::swapEyes = ::config["engine"]["ext"]["vr"]["swap eyes"].asBool();
// ext::openvr::dominantEye = ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "left" ? 0 : 1;
if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "left" ) ext::openvr::dominantEye = 0;
if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "right" ) ext::openvr::dominantEye = 1;
if ( ::config["engine"]["ext"]["vr"]["dominatEye"].isNumeric() )
ext::openvr::dominantEye = ::config["engine"]["ext"]["vr"]["dominatEye"].asUInt64();
else if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "left" ) ext::openvr::dominantEye = 0;
else if ( ::config["engine"]["ext"]["vr"]["dominatEye"].asString() == "right" ) ext::openvr::dominantEye = 1;
ext::openvr::driver.manifest = ::config["engine"]["ext"]["vr"]["manifest"].asString();
if ( ext::openvr::enabled ) {
::config["engine"]["render modes"]["stereo deferred"] = true;
// ext::vulkan::validation = false;
// if ( ::config["engine"]["ext"]["vr"]["invert winding order"].asBool() )
// ext::vulkan::GraphicOld::DEFAULT_WINDING_ORDER = VK_FRONT_FACE_COUNTER_CLOCKWISE;
}
}
/* Create initial scene (kludge) */ {
uf::Scene* scene = new uf::Scene;
uf::scene::scenes.push_back(scene);
auto& metadata = scene->getComponent<uf::Serializer>();
metadata["system"]["config"] = ::config;
}
/* Initialize Vulkan */ {
// ext::vulkan::width = ::config["window"]["size"]["x"].asInt();
// ext::vulkan::height = ::config["window"]["size"]["y"].asInt();
@ -137,11 +147,15 @@ void EXT_API ext::initialize() {
ext::vulkan::addRenderMode( renderMode, "Gui" );
renderMode->blitter.descriptor.subpass = 1;
}
if ( ::config["engine"]["render modes"]["stereo deferred"].asBool() )
ext::vulkan::addRenderMode( new ext::vulkan::StereoscopicDeferredRenderMode, "" );
else if ( ::config["engine"]["render modes"]["deferred"].asBool() )
ext::vulkan::addRenderMode( new ext::vulkan::DeferredRenderMode, "" );
// if ( ::config["engine"]["render modes"]["compute"].asBool() )
// ext::vulkan::addRenderMode( new ext::vulkan::ComputeRenderMode, "C:RT:0" );
if ( ext::openvr::enabled ) {
ext::openvr::initialize();
@ -168,19 +182,24 @@ void EXT_API ext::initialize() {
}
/* Initialize root scene*/ {
uf::scene::loadScene( ::config["engine"]["scenes"]["start"].asString() );
uf::scene::unloadScene();
auto& scene = uf::scene::loadScene( ::config["engine"]["scenes"]["start"].asString() );
auto& metadata = scene.getComponent<uf::Serializer>();
metadata["system"]["config"] = ::config;
}
/* Add hooks */ {
uf::hooks.addHook( "game:LoadScene", [&](const std::string& event)->std::string{
uf::Serializer json = event;
uf::scene::unloadScene();
uf::scene::loadScene( json["scene"].asString() );
auto& scene = uf::scene::loadScene( json["scene"].asString() );
auto& metadata = scene.getComponent<uf::Serializer>();
metadata["system"]["config"] = ::config;
return "true";
});
uf::hooks.addHook( "system:Quit", [&](const std::string& event)->std::string{
std::cout << event << std::endl;
std::cout << "system:Quit: " << event << std::endl;
ext::ready = false;
return "true";
});

View File

@ -0,0 +1,320 @@
#include "scene.h"
#include <uf/utils/time/time.h>
#include <uf/utils/io/iostream.h>
#include <uf/utils/math/vector.h>
#include <uf/utils/math/transform.h>
#include <uf/utils/window/window.h>
#include <uf/utils/audio/audio.h>
#include <uf/utils/thread/thread.h>
#include <uf/utils/camera/camera.h>
#include <uf/engine/asset/asset.h>
#include <uf/engine/asset/masterdata.h>
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/deferred.h>
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
#include <uf/ext/vulkan/rendermodes/compute.h>
#include <uf/ext/vulkan/rendermodes/stereoscopic_deferred.h>
#include <uf/ext/gltf/gltf.h>
#include <uf/utils/math/collision.h>
#include "../../ext.h"
#include "../../gui/gui.h"
EXT_OBJECT_REGISTER_CPP(RaytracedScene)
void ext::RaytracedScene::initialize() {
uf::Scene::initialize();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Asset& assetLoader = this->getComponent<uf::Asset>();
{
auto& renderMode = this->getComponent<ext::vulkan::ComputeRenderMode>();
std::string name = "C:RT:" + std::to_string((int) this->getUid());
ext::vulkan::addRenderMode( &renderMode, name );
if ( metadata["light"]["shadows"]["resolution"].isArray() ) {
renderMode.width = metadata["light"]["shadows"]["resolution"][0].asUInt64();
renderMode.height = metadata["light"]["shadows"]["resolution"][1].asUInt64();
} else {
renderMode.width = metadata["light"]["shadows"]["resolution"].asUInt64();
renderMode.height = metadata["light"]["shadows"]["resolution"].asUInt64();
}
{
struct Shape {
pod::Vector4f values;
pod::Vector3f diffuse;
float specular;
uint32_t id;
pod::Vector3ui _pad;
};
std::vector<Shape> shapes;
{
shapes.push_back( {{1.75f, -0.5f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f}, 32.0f, 1} );
shapes.push_back( {{0.0f, 1.0f, -0.5f, 1.0f }, {0.65f, 0.77f, 0.97f}, 32.0f, 1} );
shapes.push_back( {{-1.75f, -0.75f, -0.5f, 1.25f }, { 0.9f, 0.76f, 0.46f}, 32.0f, 1} );
}
{
float roomDim = 12.0f;
shapes.push_back( {{0.0f, 1.0f, 0.0f, roomDim}, {1.0f, 1.0f, 1.0f}, 32.0f, 2} );
shapes.push_back( {{0.0f, -1.0f, 0.0f, roomDim}, {1.0f, 1.0f, 1.0f}, 32.0f, 2} );
shapes.push_back( {{0.0f, 0.0f, 1.0f, roomDim}, {1.0f, 1.0f, 1.0f}, 32.0f, 2} );
shapes.push_back( {{0.0f, 0.0f, -1.0f, roomDim}, {0.0f, 0.0f, 0.0f}, 32.0f, 2} );
shapes.push_back( {{-1.0f, 0.0f, 0.0f, roomDim}, {1.0f, 0.0f, 0.0f}, 32.0f, 2} );
shapes.push_back( {{1.0f, 0.0f, 0.0f, roomDim}, {0.0f, 1.0f, 0.0f}, 32.0f, 2} );
}
renderMode.compute.device = &ext::vulkan::device;
renderMode.compute.initializeBuffer(
(void*) shapes.data(),
shapes.size() * sizeof(Shape),
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
true
);
}
}
this->addHook( "system:Quit.%UID%", [&](const std::string& event)->std::string{
std::cout << event << std::endl;
ext::ready = false;
return "true";
});
{
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
this->addHook( "world:Entity.LoadAsset", [&](const std::string& event)->std::string{
uf::Serializer json = event;
std::string asset = json["asset"].asString();
std::string uid = json["uid"].asString();
assetLoader.load(asset, "asset:Load." + uid);
return "true";
});
}
{
static uf::Timer<long long> timer(false);
if ( !timer.running() ) timer.start();
this->addHook( "menu:Pause", [&](const std::string& event)->std::string{
if ( timer.elapsed().asDouble() < 1 ) return "false";
timer.reset();
uf::Serializer json = event;
ext::Gui* manager = (ext::Gui*) this->findByName("Gui Manager");
if ( !manager ) return "false";
uf::Serializer payload;
ext::Gui* gui = (ext::Gui*) manager->findByUid( (payload["uid"] = manager->loadChild("/scenes/world/gui/pause/menu.json", false)).asUInt64() );
uf::Serializer& metadata = gui->getComponent<uf::Serializer>();
metadata["menu"] = json["menu"];
gui->initialize();
return payload;
});
}
/* store viewport size */ {
metadata["window"]["size"]["x"] = ext::vulkan::width;
metadata["window"]["size"]["y"] = ext::vulkan::height;
this->addHook( "window:Resized", [&](const std::string& event)->std::string{
uf::Serializer json = event;
pod::Vector2ui size; {
size.x = json["window"]["size"]["x"].asUInt64();
size.y = json["window"]["size"]["y"].asUInt64();
}
metadata["window"] = json["window"];
return "true";
});
}
// lock control
{
uf::Serializer payload;
payload["state"] = true;
uf::hooks.call("window:Mouse.CursorVisibility", payload);
uf::hooks.call("window:Mouse.Lock");
}
}
void ext::RaytracedScene::render() {
uf::Scene::render();
}
void ext::RaytracedScene::destroy() {
if ( this->hasComponent<ext::vulkan::ComputeRenderMode>() ) {
auto& renderMode = this->getComponent<ext::vulkan::ComputeRenderMode>();
ext::vulkan::removeRenderMode( &renderMode, false );
}
uf::Scene::destroy();
}
void ext::RaytracedScene::tick() {
uf::Scene::tick();
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
uf::Asset& assetLoader = this->getComponent<uf::Asset>();
#if 1
if ( this->hasComponent<ext::vulkan::ComputeRenderMode>() ) {
auto& renderMode = this->getComponent<ext::vulkan::ComputeRenderMode>();
/* Add lights to scene */ if ( renderMode.compute.initialized ) {
struct UniformDescriptor {
alignas(16) pod::Matrix4f matrices[2];
alignas(16) pod::Vector4f ambient;
struct Light {
alignas(16) pod::Vector4f position;
alignas(16) pod::Vector4f color;
alignas(8) pod::Vector2i type;
alignas(16) pod::Matrix4f view;
alignas(16) pod::Matrix4f projection;
} lights;
};
struct SpecializationConstant {
int32_t eyes = 2;
int32_t maxLights = 16;
} specializationConstants;
auto& shader = renderMode.compute.material.shaders.front();
specializationConstants = shader.specializationConstants.get<SpecializationConstant>();
auto& scene = uf::scene::getCurrentScene();
auto& controller = *scene.getController();
auto& camera = controller.getComponent<uf::Camera>();
auto& transform = controller.getComponent<pod::Transform<>>();
auto& userdata = shader.uniforms.front();
size_t uniforms_len = userdata.data().len;
uint8_t* uniforms_buffer = (uint8_t*) (void*) userdata;
UniformDescriptor* uniforms = (UniformDescriptor*) uniforms_buffer;
for ( size_t i = 0; i < 2; ++i ) {
uniforms->matrices[i] = uf::matrix::inverse( camera.getProjection(i) * camera.getView(i) );
}
// uniforms->lights.position = { 0, 0, 0, 32 };
// uniforms->lights.color = { 1, 1, 1, 1 };
std::vector<uf::Entity*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
if ( !entity || entity->getName() != "Light" ) return;
entities.push_back(entity);
};
for ( uf::Scene* scene : ext::vulkan::scenes ) { if ( !scene ) continue;
scene->process(filter);
}
{
const pod::Vector3& position = controller.getComponent<pod::Transform<>>().position;
std::sort( entities.begin(), entities.end(), [&]( const uf::Entity* l, const uf::Entity* r ){
if ( !l ) return false; if ( !r ) return true;
if ( !l->hasComponent<pod::Transform<>>() ) return false; if ( !r->hasComponent<pod::Transform<>>() ) return true;
return uf::vector::magnitude( uf::vector::subtract( l->getComponent<pod::Transform<>>().position, position ) ) < uf::vector::magnitude( uf::vector::subtract( r->getComponent<pod::Transform<>>().position, position ) );
} );
}
{
uf::Serializer& metadata = controller.getComponent<uf::Serializer>();
if ( metadata["light"]["should"].asBool() ) entities.push_back(&controller);
}
UniformDescriptor::Light* lights = (UniformDescriptor::Light*) &uniforms_buffer[sizeof(UniformDescriptor) - sizeof(UniformDescriptor::Light)];
for ( size_t i = 0; i < specializationConstants.maxLights && i < entities.size(); ++i ) {
UniformDescriptor::Light& light = lights[i];
uf::Entity* entity = entities[i];
pod::Transform<>& transform = entity->getComponent<pod::Transform<>>();
uf::Serializer& metadata = entity->getComponent<uf::Serializer>();
uf::Camera& camera = entity->getComponent<uf::Camera>();
light.position.x = transform.position.x;
light.position.y = transform.position.y;
light.position.z = transform.position.z;
if ( entity == &controller ) light.position.y += 2;
light.position.w = metadata["light"]["radius"].asFloat();
light.color.x = metadata["light"]["color"][0].asFloat();
light.color.y = metadata["light"]["color"][1].asFloat();
light.color.z = metadata["light"]["color"][2].asFloat();
light.color.w = metadata["light"]["power"].asFloat();
}
shader.updateBuffer( (void*) uniforms_buffer, uniforms_len, 0, false );
}
}
#endif
/* Regain control if nothing requests it */ {
ext::Gui* menu = (ext::Gui*) this->findByName("Gui: Menu");
if ( !menu ) {
uf::Serializer payload;
payload["state"] = false;
uf::hooks.call("window:Mouse.CursorVisibility", payload);
uf::hooks.call("window:Mouse.Lock");
}
}
/* Updates Sound Listener */ {
pod::Transform<>& transform = this->getController()->getComponent<pod::Transform<>>();
ext::oal.listener( "POSITION", { transform.position.x, transform.position.y, transform.position.z } );
ext::oal.listener( "VELOCITY", { 0, 0, 0 } );
ext::oal.listener( "ORIENTATION", { 0, 0, 1, 1, 0, 0 } );
}
/* Collision */ {
bool local = false;
bool sort = false;
bool useStrongest = false;
// pod::Thread& thread = uf::thread::fetchWorker();
pod::Thread& thread = uf::thread::has("Physics") ? uf::thread::get("Physics") : uf::thread::create( "Physics", true, false );
auto function = [&]() -> int {
std::vector<uf::Object*> entities;
std::function<void(uf::Entity*)> filter = [&]( uf::Entity* entity ) {
auto& metadata = entity->getComponent<uf::Serializer>();
if ( !metadata["system"]["physics"]["collision"].isNull() && !metadata["system"]["physics"]["collision"].asBool() ) return;
if ( entity->hasComponent<uf::Collider>() )
entities.push_back((uf::Object*) entity);
};
this->process(filter);
auto onCollision = []( pod::Collider::Manifold& manifold, uf::Object* a, uf::Object* b ){
uf::Serializer payload;
payload["normal"][0] = manifold.normal.x;
payload["normal"][1] = manifold.normal.y;
payload["normal"][2] = manifold.normal.z;
payload["entity"] = b->getUid();
payload["depth"] = -manifold.depth;
a->callHook("world:Collision.%UID%", payload);
payload["entity"] = a->getUid();
payload["depth"] = manifold.depth;
b->callHook("world:Collision.%UID%", payload);
};
auto testColliders = [&]( uf::Collider& colliderA, uf::Collider& colliderB, uf::Object* a, uf::Object* b, bool useStrongest ){
pod::Collider::Manifold strongest;
auto manifolds = colliderA.intersects(colliderB);
for ( auto manifold : manifolds ) {
if ( manifold.colliding && manifold.depth > 0 ) {
if ( !useStrongest ) onCollision(manifold, a, b);
else if ( strongest.depth < manifold.depth ) strongest = manifold;
}
}
if ( useStrongest && strongest.colliding ) onCollision(strongest, a, b);
};
// collide with others
for ( auto* _a : entities ) {
uf::Object& entityA = *_a;
for ( auto* _b : entities ) { if ( _a == _b ) continue;
uf::Object& entityB = *_b;
testColliders( entityA.getComponent<uf::Collider>(), entityB.getComponent<uf::Collider>(), &entityA, &entityB, useStrongest );
}
}
return 0;
};
if ( local ) function(); else uf::thread::add( thread, function, true );
}
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <uf/config.h>
#include <uf/ext/ext.h>
#include <uf/engine/object/object.h>
#include <uf/engine/scene/scene.h>
namespace ext {
class EXT_API RaytracedScene : public uf::Scene {
public:
virtual void initialize();
virtual void tick();
virtual void render();
virtual void destroy();
};
}

View File

@ -293,26 +293,6 @@ void ext::World::tick() {
ext::oal.listener( "VELOCITY", { 0, 0, 0 } );
ext::oal.listener( "ORIENTATION", { 0, 0, 1, 1, 0, 0 } );
}
/**/ if ( false ) {
uf::Serializer& metadata = this->getComponent<uf::Serializer>();
auto& scene = *this;
std::vector<ext::vulkan::Graphic*> blitters;
auto& renderMode = ext::vulkan::getRenderMode("", true);
if ( renderMode.getType() == "Deferred (Stereoscopic)" ) {
auto* renderModePointer = (ext::vulkan::StereoscopicDeferredRenderMode*) &renderMode;
blitters.push_back(&renderModePointer->blitters.left);
blitters.push_back(&renderModePointer->blitters.right);
} else if ( renderMode.getType() == "Deferred" ) {
auto* renderModePointer = (ext::vulkan::DeferredRenderMode*) &renderMode;
blitters.push_back(&renderModePointer->blitter);
}
for ( size_t _ = 0; _ < blitters.size(); ++_ ) {
auto& blitter = *blitters[_];
blitter.getPipeline().update( blitter );
}
}
}
void ext::World::render() {