Commit for 2020.09.20.7z
This commit is contained in:
parent
e16ade7185
commit
177bc46065
23
bin/data/shaders/display.blit.frag.glsl
Normal file
23
bin/data/shaders/display.blit.frag.glsl
Normal 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;
|
||||
}
|
16
bin/data/shaders/display.blit.vert.glsl
Normal file
16
bin/data/shaders/display.blit.vert.glsl
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
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;
|
||||
|
||||
// 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 );
|
||||
Shape shape = shapes[result.id];
|
||||
vec3 position = rayO + result.t * rayD;
|
||||
vec3 normal = shapeNormal( position, shape );
|
||||
|
||||
vec3 color = vec3(0.0);
|
||||
if ( objectID == UINT32_MAX ) return color;
|
||||
for ( uint i = 0; i < LIGHTS; ++i ) {
|
||||
Light light = ubo.lights[i];
|
||||
if ( light.radius <= EPSILON ) continue;
|
||||
if ( light.power <= EPSILON ) continue;
|
||||
|
||||
vec3 pos = rayO + t * rayD;
|
||||
vec3 normal;
|
||||
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;
|
||||
|
||||
// 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;
|
||||
vec4 albedoSpecular = shape.albedoSpecular;
|
||||
|
||||
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;
|
||||
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.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;
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
imageStore(resultImage, ivec2(gl_GlobalInvocationID.xy), vec4(finalColor, 0.0));
|
||||
// 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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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,
|
||||
|
@ -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 );
|
||||
};
|
||||
}
|
||||
}
|
23
engine/inc/uf/ext/vulkan/rendermodes/compute.h
Normal file
23
engine/inc/uf/ext/vulkan/rendermodes/compute.h
Normal 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 );
|
||||
};
|
||||
}
|
||||
}
|
@ -20,6 +20,7 @@ namespace ext {
|
||||
virtual void tick();
|
||||
virtual void destroy();
|
||||
virtual void render();
|
||||
virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 );
|
||||
};
|
||||
}
|
||||
}
|
@ -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 );
|
||||
|
@ -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 );
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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, ©Region);
|
||||
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, ©Region);
|
||||
device->flushCommandBuffer(copyCmd, queue, true);
|
||||
device->flushCommandBuffer(copyCmd, true);
|
||||
staging.destroy();
|
||||
}
|
@ -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, " " );
|
||||
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;
|
||||
|
||||
// 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] ) );
|
||||
|
||||
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;
|
||||
}
|
||||
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 );
|
||||
|
@ -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,7 +80,8 @@ 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: {
|
||||
|
@ -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 ) {
|
||||
@ -163,3 +164,5 @@ 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 ) {
|
||||
}
|
211
engine/src/ext/vulkan/rendermodes/compute.cpp
Normal file
211
engine/src/ext/vulkan/rendermodes/compute.cpp
Normal 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]));
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,7 +475,7 @@ 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 );
|
||||
|
||||
@ -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 );
|
||||
|
@ -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 );
|
||||
|
43
ext/main.cpp
43
ext/main.cpp
@ -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";
|
||||
});
|
||||
|
320
ext/scenes/raytrace/scene.cpp
Normal file
320
ext/scenes/raytrace/scene.cpp
Normal 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 );
|
||||
}
|
||||
}
|
16
ext/scenes/raytrace/scene.h
Normal file
16
ext/scenes/raytrace/scene.h
Normal 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();
|
||||
};
|
||||
}
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user