lots of changes (physics tweaks, actually use dynamic buffers for UBOs, perf bottleneck fixed, bug fixes, etc)
This commit is contained in:
parent
012cddd37f
commit
42aaf444ff
@ -9,8 +9,8 @@
|
||||
"max": 32,
|
||||
"shadows": {
|
||||
"enabled": true,
|
||||
"update": 4,
|
||||
"max": 8,
|
||||
"update": 8,
|
||||
"max": 32,
|
||||
"samples": 2
|
||||
},
|
||||
"bloom": {
|
||||
@ -101,7 +101,7 @@
|
||||
"experimental": {
|
||||
"rebuild on tick begin": false,
|
||||
"batch queue submissions": true,
|
||||
"dedicated thread": false,
|
||||
"dedicated thread": false, // mostly works
|
||||
"memory budget": false,
|
||||
"register render modes": true,
|
||||
"skip render on rebuild": false
|
||||
@ -115,7 +115,7 @@
|
||||
"pipelines": {
|
||||
"deferred": true,
|
||||
"gui": true,
|
||||
"vsync": false, // vsync on vulkan side rather than engine-side
|
||||
"vsync": true, // vsync on vulkan side rather than engine-side
|
||||
"hdr": true,
|
||||
"vxgi": true,
|
||||
"culling": true,
|
||||
|
||||
@ -8,8 +8,8 @@
|
||||
"physics": {
|
||||
"mass": 0,
|
||||
"inertia": false,
|
||||
// "type": "bounding box"
|
||||
"type": "mesh"
|
||||
"type": "bounding box"
|
||||
// "type": "mesh"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -37,7 +37,7 @@
|
||||
"dialogue": "/gui/dialogue/main.json"
|
||||
},
|
||||
"light": {
|
||||
"enabled": true,
|
||||
"0-enabled": true,
|
||||
|
||||
"ambient": [ 0.1, 0.1, 0.1 ],
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
"size": 8,
|
||||
"smoothness": 0.5
|
||||
},
|
||||
"shadows": {
|
||||
"0-shadows": {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#extension GL_EXT_samplerless_texture_functions : enable
|
||||
|
||||
layout (constant_id = 0) const uint PASSES = 6;
|
||||
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
||||
layout (local_size_x = 32, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
#define COMPUTE 1
|
||||
#define QUERY_MIPMAPS 1
|
||||
@ -90,14 +90,9 @@ bool frustumCull( uint id ) {
|
||||
|
||||
if ( drawCommand.indices == 0 || drawCommand.vertices == 0 ) return false;
|
||||
|
||||
bool visible = false;
|
||||
bool visible = true;
|
||||
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
|
||||
#if 0
|
||||
vec4 sphere = aabbToSphere( instance.bounds );
|
||||
vec3 center = vec3( camera.viewport[pass].view * object.model * vec4( ) );
|
||||
#else
|
||||
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * object.model;
|
||||
#if 1
|
||||
vec4 planes[6]; {
|
||||
for (int i = 0; i < 3; ++i)
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
@ -108,48 +103,18 @@ bool frustumCull( uint id ) {
|
||||
planes[i*2+j] = normalizePlane( planes[i*2+j] );
|
||||
}
|
||||
}
|
||||
bool insideFrustum = true;
|
||||
for ( uint p = 0; p < 6; ++p ) {
|
||||
float d = max(instance.bounds.min.x * planes[p].x, instance.bounds.max.x * planes[p].x)
|
||||
+ max(instance.bounds.min.y * planes[p].y, instance.bounds.max.y * planes[p].y)
|
||||
+ max(instance.bounds.min.z * planes[p].z, instance.bounds.max.z * planes[p].z);
|
||||
if ( d > -planes[p].w ) return true;
|
||||
|
||||
if (d < -planes[p].w) {
|
||||
visible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
vec4 corners[8] = {
|
||||
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
|
||||
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.min.z, 1.0 ),
|
||||
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
|
||||
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.min.z, 1.0 ),
|
||||
|
||||
vec4( instance.bounds.min.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
|
||||
vec4( instance.bounds.max.x, instance.bounds.min.y, instance.bounds.max.z, 1.0 ),
|
||||
vec4( instance.bounds.max.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
|
||||
vec4( instance.bounds.min.x, instance.bounds.max.y, instance.bounds.max.z, 1.0 ),
|
||||
};
|
||||
vec4 planes[6]; {
|
||||
#pragma unroll 3
|
||||
for (int i = 0; i < 3; ++i)
|
||||
#pragma unroll 2
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
|
||||
planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
|
||||
planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
|
||||
planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
|
||||
planes[i*2+j] = normalizePlane( planes[i*2+j] );
|
||||
}
|
||||
}
|
||||
#pragma unroll 8
|
||||
for ( uint p = 0; p < 8; ++p ) corners[p] = mat * corners[p];
|
||||
#pragma unroll 6
|
||||
for ( uint p = 0; p < 6; ++p ) {
|
||||
#pragma unroll 8
|
||||
for ( uint q = 0; q < 8; ++q ) {
|
||||
if ( dot( corners[q], planes[p] ) > 0 ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
if ( !visible ) break;
|
||||
}
|
||||
return visible;
|
||||
}
|
||||
@ -163,12 +128,11 @@ bool occlusionCull( uint id ) {
|
||||
|
||||
bool visible = true;
|
||||
for ( uint pass = 0; pass < PushConstant.passes; ++pass ) {
|
||||
#if 1
|
||||
vec4 aabb;
|
||||
vec4 sphere = aabbToSphere( instance.bounds );
|
||||
vec3 center = (camera.viewport[pass].view * object.model * vec4(sphere.xyz, 1)).xyz;
|
||||
float radius = (object.model * vec4(sphere.w, 0, 0, 0)).x;
|
||||
// center.y *= -1;
|
||||
|
||||
mat4 proj = camera.viewport[pass].projection;
|
||||
float znear = proj[3][2];
|
||||
float P00 = proj[0][0];
|
||||
@ -197,87 +161,6 @@ bool occlusionCull( uint id ) {
|
||||
//if the depth of the sphere is in front of the depth pyramid value, then the object is visible
|
||||
visible = visible && depthSphere >= depth - DEPTH_BIAS;
|
||||
}
|
||||
|
||||
#else
|
||||
mat4 mat = camera.viewport[pass].projection * camera.viewport[pass].view * object.model;
|
||||
vec3 boundsSize = instance.bounds.max - instance.bounds.min;
|
||||
vec3 points[8] = {
|
||||
instance.bounds.min.xyz,
|
||||
instance.bounds.min.xyz + vec3(boundsSize.x,0,0),
|
||||
instance.bounds.min.xyz + vec3(0, boundsSize.y,0),
|
||||
instance.bounds.min.xyz + vec3(0, 0, boundsSize.z),
|
||||
instance.bounds.min.xyz + vec3(boundsSize.xy,0),
|
||||
instance.bounds.min.xyz + vec3(0, boundsSize.yz),
|
||||
instance.bounds.min.xyz + vec3(boundsSize.x, 0, boundsSize.z),
|
||||
instance.bounds.min.xyz + boundsSize.xyz,
|
||||
};
|
||||
vec2 minXY = vec2(1);
|
||||
vec2 maxXY = vec2(0);
|
||||
|
||||
float minZ = 1;
|
||||
float maxZ = 0;
|
||||
|
||||
#pragma unroll 8
|
||||
for ( uint i = 0; i < 8; ++i ) {
|
||||
vec4 clip = mat * vec4( points[i], 1 );
|
||||
clip.xyz /= clip.w;
|
||||
clip.xy = clip.xy * 0.5 + 0.5;
|
||||
|
||||
minXY.x = min(minXY.x, clip.x);
|
||||
minXY.y = min(minXY.y, clip.y);
|
||||
|
||||
maxXY.x = max(maxXY.x, clip.x);
|
||||
maxXY.y = max(maxXY.y, clip.y);
|
||||
|
||||
#if INVERSE
|
||||
clip.z = 1.0 - clip.z;
|
||||
maxZ = max(maxZ, clip.z);
|
||||
#else
|
||||
minZ = min(minZ, clip.z);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ( maxXY.x <= 0 || maxXY.y <= 0 ) return false;
|
||||
if ( minXY.x >= 1 || minXY.y >= 1 ) return false;
|
||||
|
||||
ivec2 depthSize = textureSize( samplerDepth, 0 );
|
||||
float mips = mipLevels( depthSize );
|
||||
|
||||
vec4 uv = vec4(minXY, maxXY);
|
||||
|
||||
ivec2 clipSize = ivec2(maxXY - minXY) * depthSize;
|
||||
float mip = mipLevels( clipSize );
|
||||
mip = clamp( mip, 0, mips );
|
||||
if ( mip == 0 ) {
|
||||
mip = 1;
|
||||
} else {
|
||||
float lower = max(mip - 1, 0);
|
||||
float scale = exp2(-lower);
|
||||
vec2 a = floor(uv.xy * scale);
|
||||
vec2 b = ceil(uv.zw * scale);
|
||||
vec2 dims = b - a;
|
||||
|
||||
// Use the lower level if we only touch <= 2 texels in both dimensions
|
||||
if (dims.x <= 2 && dims.y <= 2) mip = lower;
|
||||
}
|
||||
|
||||
float depths[4] = {
|
||||
textureLod( samplerDepth, uv.xy, mip ).r,
|
||||
textureLod( samplerDepth, uv.zy, mip ).r,
|
||||
textureLod( samplerDepth, uv.xw, mip ).r,
|
||||
textureLod( samplerDepth, uv.zw, mip ).r,
|
||||
};
|
||||
#if INVERSE
|
||||
float minDepth = 1.0 - min(min(min(depths[0], depths[1]), depths[2]), depths[3]);
|
||||
#else
|
||||
float maxDepth = max(max(max(depths[0], depths[1]), depths[2]), depths[3]);
|
||||
#endif
|
||||
|
||||
instances[drawCommand.instanceID].bounds.padding1 = minZ;
|
||||
instances[drawCommand.instanceID].bounds.padding2 = maxDepth;
|
||||
|
||||
return minZ <= maxDepth;
|
||||
#endif
|
||||
}
|
||||
return visible;
|
||||
}
|
||||
@ -288,90 +171,5 @@ void main() {
|
||||
|
||||
bool visible = frustumCull( gID );
|
||||
// if ( visible ) visible = occlusionCull( gID );
|
||||
// bool visible = occlusionCull( gID );
|
||||
drawCommands[gID].instances = visible ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Frustum frustum;
|
||||
for (int i = 0; i < 3; ++i)
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
frustum.planes[i*2+j].x = mat[0][3] + (j == 0 ? mat[0][i] : -mat[0][i]);
|
||||
frustum.planes[i*2+j].y = mat[1][3] + (j == 0 ? mat[1][i] : -mat[1][i]);
|
||||
frustum.planes[i*2+j].z = mat[2][3] + (j == 0 ? mat[2][i] : -mat[2][i]);
|
||||
frustum.planes[i*2+j].w = mat[3][3] + (j == 0 ? mat[3][i] : -mat[3][i]);
|
||||
frustum.planes[i*2+j]*= length(frustum.planes[i*2+j].xyz);
|
||||
}
|
||||
for ( uint i = 0; i < 6; ++i ) {
|
||||
vec4 plane = frustum.planes[i];
|
||||
float d = dot(instance.bounds.center, plane.xyz);
|
||||
float r = dot(instance.bounds.extent, abs(plane.xyz));
|
||||
bool inside = d + r > -plane.w;
|
||||
if ( !inside ) return 0;
|
||||
}
|
||||
return true;
|
||||
*/
|
||||
/*
|
||||
vec4 plane;
|
||||
vec4 center = vec4( (max + min) * 0.5, 1 );
|
||||
vec4 extent = vec4( (max - min) * 0.5, 1 );
|
||||
center = mat * center;
|
||||
extent = mat * extent;
|
||||
center.xyz /= center.w;
|
||||
extent.xyz /= extent.w;
|
||||
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][0]; // left
|
||||
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
|
||||
if ( visible ) return true;
|
||||
|
||||
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][0]; // right
|
||||
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
|
||||
if ( visible ) return true;
|
||||
|
||||
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][1]; // bottom
|
||||
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
|
||||
if ( visible ) return true;
|
||||
|
||||
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][1]; // top
|
||||
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
|
||||
if ( visible ) return true;
|
||||
|
||||
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] + mat[i][2]; // near
|
||||
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
|
||||
if ( visible ) return true;
|
||||
|
||||
for (int i = 0; i < 4; ++i ) plane[i] = mat[i][3] - mat[i][2]; // far
|
||||
visible = dot(center.xyz + extent.xyz * sign(plane.xyz), plane.xyz ) > -plane.w;
|
||||
if ( visible ) return true;
|
||||
|
||||
*/
|
||||
/*
|
||||
for ( uint p = 0; p < 8; ++p ) {
|
||||
vec4 t = corners[p];
|
||||
float w = abs(t.w);
|
||||
visible = -w <= t.x && t.x <= w && -w <= t.y && t.y <= w && 0 <= t.z && t.z <= w; // && -w <= t.z && t.z <= w;
|
||||
}
|
||||
*/
|
||||
/*
|
||||
mat4 convert( mat4 proj ) {
|
||||
float f = -proj[1][1];
|
||||
float raidou = f / proj[0][0];
|
||||
float zNear = proj[3][2];
|
||||
float zFar = 32;
|
||||
|
||||
float range = zNear - zFar;
|
||||
|
||||
float Sx = f * raidou;
|
||||
float Sy = f;
|
||||
float Sz = (-zNear - zFar) / range;
|
||||
float Pz = 2 * zFar * zNear / range;
|
||||
|
||||
mat4 new = mat4(1.0);
|
||||
new[0][0] = Sx;
|
||||
new[1][1] = -Sy;
|
||||
new[2][2] = Sz;
|
||||
new[3][2] = Pz;
|
||||
new[2][3] = 1;
|
||||
return new;
|
||||
}
|
||||
*/
|
||||
}
|
||||
@ -90,6 +90,8 @@ namespace ext {
|
||||
void UF_API terminate( uf::Object& );
|
||||
|
||||
extern UF_API float timescale;
|
||||
extern UF_API bool async;
|
||||
|
||||
extern UF_API bool interpolate;
|
||||
extern UF_API bool shared;
|
||||
extern UF_API bool globalStorage;
|
||||
|
||||
@ -18,8 +18,9 @@ namespace ext {
|
||||
0
|
||||
};
|
||||
VkDeviceSize alignment = 0;
|
||||
size_t address = {};
|
||||
mutable size_t address = {};
|
||||
void* mapped = nullptr;
|
||||
int32_t count = 1;
|
||||
|
||||
VkBufferUsageFlags usage = 0;
|
||||
VkMemoryPropertyFlags memoryProperties = 0;
|
||||
@ -29,25 +30,19 @@ namespace ext {
|
||||
|
||||
void* map( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 );
|
||||
void unmap();
|
||||
// void* map( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 ) const;
|
||||
// void unmap() const;
|
||||
// VkResult bind( VkDeviceSize offset = 0 );
|
||||
// void copyTo( void* data, VkDeviceSize size );
|
||||
// VkResult flush( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 ) const;
|
||||
// VkResult invalidate( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 );
|
||||
|
||||
|
||||
void updateDescriptor( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 );
|
||||
void allocate( VkBufferCreateInfo );
|
||||
|
||||
uint64_t getAddress();
|
||||
uint64_t getAddress() const;
|
||||
|
||||
VkDeviceSize getLength() const; // returns the aligned length for the entire buffer
|
||||
VkDeviceSize getOffset( size_t = 0 ) const; // returns the offset / stride / length of one object within the buffer
|
||||
|
||||
// RAII
|
||||
~Buffer();
|
||||
void initialize( ext::vulkan::Device& device, size_t = {} );
|
||||
void initialize( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool = VK_DEFAULT_STAGE_BUFFERS );
|
||||
bool update( const void*, VkDeviceSize, bool = VK_DEFAULT_STAGE_BUFFERS ) const;
|
||||
bool update( const void*, VkDeviceSize, bool = VK_DEFAULT_STAGE_BUFFERS ) const; // returns true if a reallocation occurred (to signal rebuilding command buffers)
|
||||
void destroy(bool = VK_DEFAULT_DEFER_BUFFER_DESTROY);
|
||||
|
||||
void swap( Buffer& );
|
||||
|
||||
@ -38,12 +38,14 @@ namespace ext {
|
||||
void initialize( const Graphic& graphic, const GraphicDescriptor& descriptor );
|
||||
void update( const Graphic& graphic );
|
||||
void update( const Graphic& graphic, const GraphicDescriptor& descriptor );
|
||||
void record( const Graphic& graphic, VkCommandBuffer, size_t = 0, size_t = 0 ) const;
|
||||
void record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer, size_t = 0, size_t = 0 ) const;
|
||||
void record( const Graphic& graphic, VkCommandBuffer, size_t = 0, size_t = 0, size_t = 0 ) const;
|
||||
void record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer, size_t = 0, size_t = 0, size_t = 0 ) const;
|
||||
void destroy();
|
||||
|
||||
uf::stl::vector<Shader*> getShaders( uf::stl::vector<Shader>& );
|
||||
uf::stl::vector<const Shader*> getShaders( const uf::stl::vector<Shader>& ) const;
|
||||
|
||||
void collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const;
|
||||
};
|
||||
|
||||
struct UF_API Material {
|
||||
@ -114,8 +116,9 @@ namespace ext {
|
||||
|
||||
void updatePipelines();
|
||||
|
||||
void record( VkCommandBuffer commandBuffer, size_t pass = 0, size_t draw = 0 ) const;
|
||||
void record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0 ) const;
|
||||
void record( VkCommandBuffer commandBuffer, size_t pass = 0, size_t draw = 0, size_t offset = 0 ) const;
|
||||
void record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass = 0, size_t draw = 0, size_t offset = 0 ) const;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,14 @@
|
||||
#include <uf/ext/vulkan/texture.h>
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
|
||||
#define VK_COMMAND_BUFFER_CALLBACK( pass, commandBuffer, i, f ) {\
|
||||
auto it = commandBufferCallbacks.find(pass);\
|
||||
if ( it != commandBufferCallbacks.end() ) {\
|
||||
commandBufferCallbacks[pass]( commandBuffer, i );\
|
||||
f;\
|
||||
}\
|
||||
}
|
||||
|
||||
namespace ext {
|
||||
namespace vulkan {
|
||||
struct Graphic;
|
||||
@ -54,8 +62,9 @@ namespace ext {
|
||||
Device* device = VK_NULL_HANDLE;
|
||||
RenderTarget renderTarget;
|
||||
|
||||
VkSemaphore renderCompleteSemaphore;
|
||||
uf::stl::vector<VkSemaphore> renderCompleteSemaphores;
|
||||
uf::stl::vector<VkFence> fences;
|
||||
uf::renderer::QueueEnum queueEnum = {};
|
||||
|
||||
typedef uf::stl::vector<VkCommandBuffer> commands_container_t;
|
||||
std::thread::id mostRecentCommandPoolId;
|
||||
|
||||
@ -124,6 +124,8 @@ namespace ext {
|
||||
uf::stl::vector<AttachmentDescriptor> attachments;
|
||||
uf::stl::vector<BufferDescriptor> buffers;
|
||||
} aliases;
|
||||
|
||||
uf::stl::vector<uint32_t> dynamicRanges;
|
||||
} metadata;
|
||||
|
||||
ext::vulkan::userdata_t specializationConstants;
|
||||
@ -177,7 +179,6 @@ namespace ext {
|
||||
void setSpecializationConstants( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values );
|
||||
void setDescriptorCounts( const uf::stl::unordered_map<uf::stl::string, uint32_t>& values );
|
||||
|
||||
|
||||
/*
|
||||
uf::Serializer getUniformJson( const uf::stl::string& name, bool cache = true );
|
||||
bool updateUniform( const uf::stl::string& name, const ext::json::Value& payload );
|
||||
|
||||
@ -13,11 +13,10 @@ namespace ext {
|
||||
bool initialized = false;
|
||||
uint32_t buffers = {};
|
||||
|
||||
VkSemaphore presentCompleteSemaphore;
|
||||
VkSemaphore renderCompleteSemaphore;
|
||||
uf::stl::vector<VkSemaphore> presentCompleteSemaphores;
|
||||
|
||||
// helpers
|
||||
VkResult acquireNextImage( uint32_t* imageIndex, VkSemaphore );
|
||||
VkResult acquireNextImage( uint32_t* imageIndex, VkSemaphore, VkFence = nullptr );
|
||||
VkResult queuePresent( VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore = VK_NULL_HANDLE );
|
||||
|
||||
// RAII
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
#define VK_DEFAULT_STAGE_BUFFERS ext::vulkan::settings::defaultStageBuffers
|
||||
#define VK_DEFAULT_DEFER_BUFFER_DESTROY ext::vulkan::settings::defaultDeferBufferDestroy
|
||||
#define VK_DEFAULT_COMMAND_BUFFER_IMMEDIATE ext::vulkan::settings::defaultCommandBufferImmediate
|
||||
#define VK_UBO_USE_N_BUFFERS 1
|
||||
|
||||
namespace ext {
|
||||
namespace vulkan {
|
||||
|
||||
@ -227,6 +227,50 @@ namespace pod {
|
||||
pod::BVH::pairs_t pairs;
|
||||
};
|
||||
|
||||
struct PhysicsSettings {
|
||||
bool warmupSolver = true; // cache manifold data to warm up the solver
|
||||
bool blockContactSolver = true; // use BlockNxN solvers (where N = number of contacts for a manifold)
|
||||
bool psgContactSolver = true; // use PSG contact solver
|
||||
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
|
||||
bool fixedStep = true; // run physics simulation with a fixed delta time (with accumulation), rather than rely on actual engine deltatime
|
||||
uint32_t substeps = 4; // number of substeps per frame tick
|
||||
uint32_t reserveCount = 32; // amount of elements to reserve for vectors used in this system, to-do: have it tie to a memory pool allocator
|
||||
|
||||
// increasing these make things lag for reasons I can imagine why
|
||||
uint32_t broadphaseBvhCapacity = 4; // number of bodies per leaf node
|
||||
uint32_t meshBvhCapacity = 4; // number of triangles per leaf node
|
||||
|
||||
// additionally flattens a BVH for linear iteration, rather than a recursive / stack-based traversal
|
||||
bool flattenBvhBodies = true;
|
||||
bool flattenBvhMeshes = true;
|
||||
|
||||
// use surface area heuristics for building the BVH, rather than naive splits
|
||||
bool useBvhSahBodies = true; // it actually seems slower to use these......
|
||||
bool useBvhSahMeshes = true;
|
||||
|
||||
bool useSplitBvhs = true; // creates separate BVHs for static / dynamic objects
|
||||
|
||||
// to-do: find possibly better values for this
|
||||
uint32_t solverIterations = 10;
|
||||
float baumgarteCorrectionPercent = 0.4f;
|
||||
float baumgarteCorrectionSlop = 0.01f;
|
||||
|
||||
uf::stl::unordered_map<size_t, pod::Manifold> manifoldsCache;
|
||||
uint32_t manifoldCacheLifetime = 6; // to-do: find a good value for this
|
||||
|
||||
uint32_t frameCounter = 0;
|
||||
|
||||
// to-do: tweak this to not be annoying
|
||||
pod::BVH::UpdatePolicy bvhUpdatePolicy = {
|
||||
.displacementThreshold = 0.25f,
|
||||
.overlapThreshold = 2.0f,
|
||||
.dirtyRatioThreshold = 0.3f,
|
||||
.maxFramesBeforeRebuild = 60, // * 10, // 10 seconds
|
||||
};
|
||||
|
||||
float groundedThreshold = 0.7f; // threshold before marking a body as grounded
|
||||
};
|
||||
|
||||
struct World {
|
||||
uf::stl::vector<pod::PhysicsBody*> bodies;
|
||||
|
||||
@ -240,11 +284,14 @@ namespace uf {
|
||||
namespace physics {
|
||||
namespace impl {
|
||||
extern UF_API float timescale;
|
||||
extern UF_API bool async;
|
||||
|
||||
extern UF_API bool interpolate;
|
||||
extern UF_API bool shared;
|
||||
extern UF_API bool globalStorage;
|
||||
|
||||
extern UF_API pod::World world;
|
||||
extern UF_API pod::PhysicsSettings settings;
|
||||
|
||||
void UF_API initialize();
|
||||
void UF_API initialize( uf::Object& );
|
||||
@ -272,7 +319,7 @@ namespace uf {
|
||||
void UF_API updateInertia( pod::PhysicsBody& body );
|
||||
|
||||
void UF_API applyForce( pod::PhysicsBody& body, const pod::Vector3f& force );
|
||||
void UF_API applyForceAtPoint( pod::PhysicsBody body, const pod::Vector3f& force, const pod::Vector3f& point );
|
||||
void UF_API applyForceAtPoint( pod::PhysicsBody& body, const pod::Vector3f& force, const pod::Vector3f& point );
|
||||
void UF_API applyImpulse( pod::PhysicsBody& body, const pod::Vector3f& impulse );
|
||||
void UF_API applyTorque( pod::PhysicsBody& body, const pod::Vector3f& torque );
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@ namespace pod {
|
||||
std::condition_variable queued;
|
||||
std::condition_variable finished;
|
||||
} conditions;
|
||||
|
||||
std::thread thread;
|
||||
|
||||
pod::Thread::queue_t queue;
|
||||
@ -47,6 +48,7 @@ namespace pod {
|
||||
|
||||
uf::Timer<long long> timer;
|
||||
uint affinity = 0;
|
||||
std::atomic<int> pending{0};
|
||||
|
||||
struct UF_API Tasks {
|
||||
uf::stl::string name = uf::thread::workerThreadName;
|
||||
@ -112,7 +114,11 @@ namespace uf {
|
||||
// schedules to named thread
|
||||
inline void queue( const uf::stl::string& name, const pod::Thread::function_t& fun ) { return uf::thread::queue( uf::thread::get(name), fun ); }
|
||||
inline void add( const uf::stl::string& name, const pod::Thread::function_t& fun ) { return uf::thread::add( uf::thread::get(name), fun ); }
|
||||
|
||||
|
||||
/*
|
||||
template<typename F>
|
||||
inline void queue( const uf::stl::string& name, const F& fun ) { return uf::thread::queue( uf::thread::get(name), [=](){ fun(); } ); }
|
||||
*/
|
||||
void UF_API process( pod::Thread& );
|
||||
|
||||
void UF_API wait( pod::Thread& );
|
||||
|
||||
@ -753,6 +753,8 @@ void UF_API uf::initialize() {
|
||||
}
|
||||
|
||||
void UF_API uf::tick() {
|
||||
++uf::time::frame;
|
||||
|
||||
#if 1
|
||||
if ( /*global*/::sceneTransition.phase >= 0 ) {
|
||||
auto target = /*global*/::sceneTransition.payload["scene"].as<uf::stl::string>();
|
||||
@ -837,13 +839,14 @@ void UF_API uf::tick() {
|
||||
lMetadata["light"]["color"][2] = (rand() % 100) / 100.0;
|
||||
}
|
||||
auto& sMetadata = scene.getComponent<uf::Serializer>();
|
||||
sMetadata["light"]["should"] = true;
|
||||
sMetadata["light"]["enabled"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Update physics timer */ {
|
||||
// uf::physics::tick();
|
||||
// to-do: add setting to either run in main thread or defer to a background thread
|
||||
uf::physics::tick();
|
||||
}
|
||||
/* Update entities */ {
|
||||
uf::scene::tick();
|
||||
|
||||
@ -40,6 +40,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
|
||||
if ( ++::roundRobin.current >= ::roundRobin.lights.size() ) ::roundRobin.current = 0;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
if ( !metadataJson["light"]["bias"]["shader"].is<float>() ) metadataJson["light"]["bias"]["shader"] = 0.000000005f;
|
||||
*/
|
||||
@ -56,7 +57,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) {
|
||||
#if UF_USE_OPENGL
|
||||
metadataJson["light"]["shadows"] = false;
|
||||
#endif
|
||||
if ( !sceneMetadataJson["lights"]["shadows"]["enabled"].as<bool>(true) ) {
|
||||
if ( !sceneMetadataJson["light"]["shadows"]["enabled"].as<bool>(true) ) {
|
||||
metadataJson["light"]["shadows"] = false;
|
||||
}
|
||||
if ( metadataJson["light"]["shadows"].as<bool>() ) {
|
||||
|
||||
@ -767,8 +767,7 @@ void ext::ExtSceneBehavior::destroy( uf::Object& self ) {
|
||||
}
|
||||
}
|
||||
void ext::ExtSceneBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ) {
|
||||
serializer["light"]["should"] = /*this->*/light.enabled;
|
||||
|
||||
serializer["light"]["enabled"] = /*this->*/light.enabled;
|
||||
serializer["light"]["ambient"] = uf::vector::encode( /*this->*/light.ambient );
|
||||
serializer["light"]["exposure"] = /*this->*/light.exposure;
|
||||
serializer["light"]["gamma"] = /*this->*/light.gamma;
|
||||
@ -834,7 +833,7 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali
|
||||
/*this->*/shadow.update = serializer["light"]["shadows"]["update"].as(/*this->*/shadow.update);
|
||||
/*this->*/shadow.typeMap = serializer["light"]["shadows"]["map type"].as(/*this->*/shadow.typeMap);
|
||||
|
||||
/*this->*/light.enabled = serializer["light"]["enabled"].as(/*this->*/light.enabled) && serializer["light"]["should"].as(/*this->*/light.enabled);
|
||||
/*this->*/light.enabled = serializer["light"]["enabled"].as(/*this->*/light.enabled) && serializer["light"]["enabled"].as(/*this->*/light.enabled);
|
||||
/*this->*/light.max = serializer["light"]["max"].as(/*this->*/light.max);
|
||||
/*this->*/light.ambient = uf::vector::decode( serializer["light"]["ambient"], /*this->*/light.ambient);
|
||||
|
||||
@ -1228,6 +1227,9 @@ void ext::ExtSceneBehavior::bindBuffers( uf::Object& self, uf::renderer::Graphic
|
||||
auto& shader = graphic.material.getShader(shaderType, shaderPipeline);
|
||||
if ( !shader.hasUniform("UBO") ) return;
|
||||
//UF_MSG_DEBUG( "{}: {} {} // {}", uf::string::toString( self ), shaderType, shaderPipeline, uf::string::toString( uf::scene::getCurrentScene() ) );
|
||||
|
||||
// if ( controller.getName() == "Player" ) UF_MSG_DEBUG("frame={}, camera={}", uf::time::frame, uf::matrix::toString( uniforms.matrices[0].view ));
|
||||
|
||||
shader.updateBuffer( (const void*) &uniforms, sizeof(uniforms), shader.getUniformBuffer("UBO") );
|
||||
|
||||
bool shouldUpdate2 = !uf::matrix::equals( uniforms.matrices[0].view, previousUniforms.matrices[0].view, 0.0001f );
|
||||
|
||||
@ -1494,7 +1494,9 @@ void uf::graph::render( uf::Object& object ) {
|
||||
}
|
||||
void uf::graph::render( pod::Graph::Storage& storage ) {
|
||||
auto* renderMode = uf::renderer::getCurrentRenderMode();
|
||||
|
||||
|
||||
if ( renderMode->getName() == "Gui" ) return;
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = scene.getCamera( controller );
|
||||
@ -1509,6 +1511,8 @@ void uf::graph::render( pod::Graph::Storage& storage ) {
|
||||
}
|
||||
#endif
|
||||
|
||||
// if ( controller.getName() == "Player" ) UF_MSG_DEBUG("frame={}, camera={}, renderMode={}, {}", uf::time::frame, uf::matrix::toString( viewport.matrices[0].view ), renderMode->getName(), renderMode->getType() );
|
||||
|
||||
storage.buffers.camera.update( (const void*) &viewport, sizeof(pod::Camera::Viewports) );
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
|
||||
@ -140,7 +140,6 @@ void uf::ObjectBehavior::initialize( uf::Object& self ) {
|
||||
pod::Vector3f min = uf::vector::decode( metadataJsonPhysics["min"], pod::Vector3f{-0.5f, -0.5f, -0.5f} );
|
||||
pod::Vector3f max = uf::vector::decode( metadataJsonPhysics["max"], pod::Vector3f{0.5f, 0.5f, 0.5f} );
|
||||
|
||||
UF_MSG_DEBUG("entity={}, min={}, max={}", uf::string::toString( *this ), uf::vector::toString( min ), uf::vector::toString( max ));
|
||||
#if UF_USE_REACTPHYSICS
|
||||
auto center = ( max + min ) * 0.5f;
|
||||
if ( metadataJsonPhysics["recenter"].as<bool>(true) ) offset = (center - transform.position);
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/renderer/renderer.h>
|
||||
#include <uf/utils/io/fmt.h>
|
||||
#include <uf/engine/ext.h>
|
||||
#include <regex>
|
||||
|
||||
UF_OBJECT_REGISTER_BEGIN(uf::Scene)
|
||||
@ -268,7 +269,7 @@ void uf::scene::tick() {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto/*&*/ graph = scene.getGraph(true);
|
||||
|
||||
uf::physics::tick( scene );
|
||||
// uf::physics::tick( scene );
|
||||
|
||||
#if !UF_SCENE_GLOBAL_GRAPH
|
||||
auto& metadata = scene.getComponent<uf::SceneBehavior::Metadata>();
|
||||
|
||||
@ -44,37 +44,13 @@ void ext::vulkan::Buffer::aliasBuffer( const ext::vulkan::Buffer& buffer ) {
|
||||
|
||||
void* ext::vulkan::Buffer::map( VkDeviceSize size, VkDeviceSize offset ) {
|
||||
if ( !mapped ) VK_CHECK_RESULT(vmaMapMemory( allocator, allocation, &mapped ));
|
||||
return mapped;
|
||||
return static_cast<char*>(mapped) + offset;;
|
||||
}
|
||||
void ext::vulkan::Buffer::unmap() {
|
||||
if ( !mapped ) return;
|
||||
vmaUnmapMemory( allocator, allocation );
|
||||
mapped = nullptr;
|
||||
}
|
||||
/*
|
||||
void* ext::vulkan::Buffer::map( VkDeviceSize size, VkDeviceSize offset ) const {
|
||||
void* mapped{};
|
||||
VK_CHECK_RESULT(vmaMapMemory( allocator, allocation, &mapped ));
|
||||
return mapped;
|
||||
}
|
||||
void ext::vulkan::Buffer::unmap() const {
|
||||
vmaUnmapMemory( allocator, allocation );
|
||||
}
|
||||
VkResult ext::vulkan::Buffer::bind( VkDeviceSize offset ) {
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
VkResult ext::vulkan::Buffer::flush( VkDeviceSize size, VkDeviceSize offset ) const {
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
VkResult ext::vulkan::Buffer::invalidate( VkDeviceSize size, VkDeviceSize offset ) {
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
void ext::vulkan::Buffer::copyTo( void* data, VkDeviceSize size ) {
|
||||
assert(mapped);
|
||||
memcpy(mapped, data, size);
|
||||
}
|
||||
*/
|
||||
|
||||
void ext::vulkan::Buffer::updateDescriptor( VkDeviceSize size, VkDeviceSize offset ) {
|
||||
descriptor.offset = offset;
|
||||
@ -95,7 +71,7 @@ void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) {
|
||||
VK_REGISTER_HANDLE( buffer );
|
||||
}
|
||||
|
||||
size_t ext::vulkan::Buffer::getAddress() {
|
||||
size_t ext::vulkan::Buffer::getAddress() const {
|
||||
// if ( !(usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) ) UF_MSG_DEBUG("CALLING GETADDRESS ON BUFFER WITHOUT ADDRESS BIT: {}", fmt::ptr(this->buffer));
|
||||
if ( this->address ) return this->address;
|
||||
|
||||
@ -104,14 +80,12 @@ size_t ext::vulkan::Buffer::getAddress() {
|
||||
info.buffer = buffer;
|
||||
return (this->address = vkGetBufferDeviceAddressKHR(this->device ? *this->device : ext::vulkan::device, &info));
|
||||
}
|
||||
size_t ext::vulkan::Buffer::getAddress() const {
|
||||
// if ( !(usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) ) UF_MSG_DEBUG("CALLING GETADDRESS ON BUFFER WITHOUT ADDRESS BIT: {}", fmt::ptr(this->buffer));
|
||||
if ( this->address ) return this->address;
|
||||
|
||||
VkBufferDeviceAddressInfoKHR info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
info.buffer = buffer;
|
||||
return vkGetBufferDeviceAddressKHR(this->device ? *this->device : ext::vulkan::device, &info);
|
||||
size_t ext::vulkan::Buffer::getLength( ) const {
|
||||
return allocationInfo.size;
|
||||
}
|
||||
size_t ext::vulkan::Buffer::getOffset( size_t i ) const {
|
||||
return this->getLength() / this->count * i;
|
||||
}
|
||||
|
||||
ext::vulkan::Buffer::~Buffer() {
|
||||
@ -147,16 +121,28 @@ void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkB
|
||||
if ( !device ) device = &ext::vulkan::device;
|
||||
if ( stage ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties
|
||||
|
||||
// if ( usage != VK_BUFFER_USAGE_TRANSFER_SRC_BIT ) usage |= VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
// assume all UBOs are dynamic
|
||||
auto totalLength = length;
|
||||
#if VK_UBO_USE_N_BUFFERS
|
||||
if ( usage & VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ) {
|
||||
this->count = ext::vulkan::swapchain.buffers;
|
||||
this->alignment = device->properties.limits.minUniformBufferOffsetAlignment;
|
||||
totalLength = ALIGNED_SIZE( length, this->alignment ) * this->count;
|
||||
}
|
||||
#endif
|
||||
|
||||
VK_CHECK_RESULT(device->createBuffer(
|
||||
nullptr,
|
||||
length,
|
||||
totalLength,
|
||||
usage,
|
||||
memoryProperties,
|
||||
*this
|
||||
));
|
||||
|
||||
if ( length != totalLength ) {
|
||||
this->updateDescriptor( length, 0 );
|
||||
}
|
||||
|
||||
if ( data && length ) update( data, length, stage );
|
||||
|
||||
/*
|
||||
@ -187,6 +173,13 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
|
||||
if ( !length ) return false;
|
||||
if ( !buffer ) return false;
|
||||
|
||||
VkDeviceSize offset = 0;
|
||||
#if VK_UBO_USE_N_BUFFERS
|
||||
if ( this->count == ext::vulkan::swapchain.buffers ) {
|
||||
offset = this->getOffset( states::currentBuffer );
|
||||
}
|
||||
#endif
|
||||
|
||||
// to-do: fix this because it's a thorn in my side when a mesh needs to update
|
||||
if ( length > allocationInfo.size ) {
|
||||
UF_MSG_WARNING("Buffer update of {} exceeds buffer size of {}", length, allocationInfo.size);
|
||||
@ -206,7 +199,7 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
|
||||
if ( !data ) return false;
|
||||
if ( !stage ) {
|
||||
auto* self = const_cast<ext::vulkan::Buffer*>(this);
|
||||
void* map = self->map();
|
||||
void* map = self->map(length, offset);
|
||||
memcpy(map, data, length);
|
||||
self->unmap();
|
||||
return false;
|
||||
@ -224,6 +217,7 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
|
||||
auto commandBuffer = device->fetchCommandBuffer(QueueEnum::TRANSFER); // waits on finish
|
||||
VkBufferCopy region = {};
|
||||
region.size = length;
|
||||
region.dstOffset = offset;
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "copyBuffer" );
|
||||
vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, 1, ®ion);
|
||||
device->flushCommandBuffer(commandBuffer);
|
||||
|
||||
@ -984,7 +984,7 @@ void ext::vulkan::Device::initialize() {
|
||||
}
|
||||
auto& deviceInfo = deviceInfos[bestDeviceIndex];
|
||||
this->physicalDevice = deviceInfo.handle;
|
||||
VK_VALIDATION_MESSAGE("Usind device #{}: (score: {} | device ID: {} | vendor ID: {} | API version: {} | driver version: {})", bestDeviceIndex, deviceInfo.properties.deviceName, deviceInfo.score, deviceInfo.properties.deviceID, deviceInfo.properties.vendorID, deviceInfo.properties.apiVersion, deviceInfo.properties.driverVersion );
|
||||
VK_VALIDATION_MESSAGE("Using device #{}: (score: {} | device ID: {} | vendor ID: {} | API version: {} | driver version: {})", bestDeviceIndex, deviceInfo.properties.deviceName, deviceInfo.score, deviceInfo.properties.deviceID, deviceInfo.properties.vendorID, deviceInfo.properties.apiVersion, deviceInfo.properties.driverVersion );
|
||||
/*
|
||||
VK_VALIDATION_MESSAGE("Using device #" << bestDeviceIndex << " ("
|
||||
"score: " << deviceInfo.score << " | "
|
||||
|
||||
@ -393,12 +393,18 @@ PIPELINE_INITIALIZATION_INVALID:
|
||||
});
|
||||
return;
|
||||
}
|
||||
void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const {
|
||||
return record( graphic, descriptor, commandBuffer, pass, draw );
|
||||
void ext::vulkan::Pipeline::record( const Graphic& graphic, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
|
||||
return record( graphic, descriptor, commandBuffer, pass, draw, offset );
|
||||
}
|
||||
void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const {
|
||||
void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescriptor& descriptor, VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
|
||||
auto shaders = getShaders( graphic.material.shaders );
|
||||
|
||||
// create dynamic offset ranges
|
||||
static thread_local uf::stl::vector<uint32_t> dynamicOffsets;
|
||||
dynamicOffsets.clear();
|
||||
|
||||
RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true);
|
||||
|
||||
bool bound = false;
|
||||
for ( auto* shader : shaders ) {
|
||||
// compute shaders
|
||||
@ -435,13 +441,23 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, size, data );
|
||||
}
|
||||
}
|
||||
|
||||
dynamicOffsets.insert( dynamicOffsets.end(), shader->metadata.dynamicRanges.begin(), shader->metadata.dynamicRanges.end() );
|
||||
}
|
||||
|
||||
for ( auto& dynamicOffset : dynamicOffsets ) {
|
||||
dynamicOffset *= offset;
|
||||
}
|
||||
|
||||
// no matching bind point for shaders, skip
|
||||
if ( !bound ) return;
|
||||
|
||||
// Bind descriptor sets describing shader binding points
|
||||
vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint)descriptor.bind.point, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
#if VK_UBO_USE_N_BUFFERS
|
||||
vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint) descriptor.bind.point, pipelineLayout, 0, 1, &descriptorSet, dynamicOffsets.size(), dynamicOffsets.data());
|
||||
#else
|
||||
vkCmdBindDescriptorSets(commandBuffer, (VkPipelineBindPoint) descriptor.bind.point, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
#endif
|
||||
// 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, (VkPipelineBindPoint)descriptor.bind.point, pipeline);
|
||||
@ -516,50 +532,10 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
auto& infos = INFOS.emplace_back();
|
||||
uf::stl::vector<ext::vulkan::enums::Image::viewType_t> types;
|
||||
|
||||
// add aliased-by-name buffers
|
||||
for ( auto& descriptor : shader->metadata.aliases.buffers ) {
|
||||
auto matches = uf::string::match(descriptor.name, R"(/^(.+?)\[(\d+)\]$/)");
|
||||
auto name = matches.size() == 2 ? matches[0] : descriptor.name;
|
||||
auto view = matches.size() == 2 ? stoi(matches[1]) : -1;
|
||||
const ext::vulkan::Buffer* buffer = &descriptor.fallback;
|
||||
if ( descriptor.renderMode ) {
|
||||
if ( descriptor.renderMode->hasBuffer(name) )
|
||||
buffer = &descriptor.renderMode->getBuffer(name);
|
||||
} else if ( renderMode.hasBuffer(name) ) {
|
||||
buffer = &renderMode.getBuffer(name);
|
||||
}
|
||||
|
||||
if ( !buffer ) continue;
|
||||
|
||||
if ( buffer->usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer->descriptor);
|
||||
if ( buffer->usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer->descriptor);
|
||||
}
|
||||
#if 0
|
||||
// add per-rendermode buffers
|
||||
for ( auto& buffer : renderMode.buffers ) {
|
||||
this->collectBuffers( *shader, renderMode, graphic, [&]( const Buffer& buffer ){
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor);
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor);
|
||||
// if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor);
|
||||
}
|
||||
#endif
|
||||
// add per-shader buffers
|
||||
for ( auto& buffer : shader->buffers ) {
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor);
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor);
|
||||
// if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor);
|
||||
}
|
||||
// add per-pipeline buffers
|
||||
for ( auto& buffer : this->buffers ) {
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor);
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor);
|
||||
// if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor);
|
||||
}
|
||||
// add per-graphics buffers
|
||||
for ( auto& buffer : graphic.buffers ) {
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::UNIFORM ) infos.uniform.emplace_back(buffer.descriptor);
|
||||
if ( buffer.usage & uf::renderer::enums::Buffer::STORAGE ) infos.storage.emplace_back(buffer.descriptor);
|
||||
// if ( buffer.usage & VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR ) infos.accelerationStructure.emplace_back(buffer.descriptor);
|
||||
}
|
||||
} );
|
||||
|
||||
if ( descriptor.subpass < renderTarget.passes.size() ) {
|
||||
auto& subpass = renderTarget.passes[descriptor.subpass];
|
||||
@ -796,7 +772,8 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
));
|
||||
samplerInfo += layout.descriptorCount;
|
||||
} break;
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
|
||||
UF_ASSERT_BREAK_MSG( uniformBufferInfo != infos.uniform.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
|
||||
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
|
||||
descriptorSet,
|
||||
@ -807,7 +784,8 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
));
|
||||
uniformBufferInfo += layout.descriptorCount;
|
||||
} break;
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
|
||||
UF_ASSERT_BREAK_MSG( storageBufferInfo != infos.storage.end(), "Filename: {}\tCount: {}", shader->filename, layout.descriptorCount )
|
||||
writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
|
||||
descriptorSet,
|
||||
@ -908,6 +886,35 @@ PIPELINE_UPDATE_INVALID:
|
||||
});
|
||||
return;
|
||||
}
|
||||
void ext::vulkan::Pipeline::collectBuffers( const Shader& shader, const RenderMode& renderMode, const Graphic& graphic, const std::function<void(const Buffer&)>& lambda ) const {
|
||||
// add aliased-by-name buffers
|
||||
for ( auto& descriptor : shader.metadata.aliases.buffers ) {
|
||||
auto matches = uf::string::match(descriptor.name, R"(/^(.+?)\[(\d+)\]$/)");
|
||||
auto name = matches.size() == 2 ? matches[0] : descriptor.name;
|
||||
auto view = matches.size() == 2 ? stoi(matches[1]) : -1;
|
||||
const ext::vulkan::Buffer* buffer = &descriptor.fallback;
|
||||
if ( descriptor.renderMode ) {
|
||||
if ( descriptor.renderMode->hasBuffer(name) )
|
||||
buffer = &descriptor.renderMode->getBuffer(name);
|
||||
} else if ( renderMode.hasBuffer(name) ) {
|
||||
buffer = &renderMode.getBuffer(name);
|
||||
}
|
||||
|
||||
if ( !buffer ) continue;
|
||||
|
||||
lambda( *buffer );
|
||||
}
|
||||
#if 0
|
||||
// add per-rendermode buffers
|
||||
for ( auto& buffer : renderMode.buffers ) lambda( buffer );
|
||||
#endif
|
||||
// add per-shader buffers
|
||||
for ( auto& buffer : shader.buffers ) lambda( buffer );
|
||||
// add per-pipeline buffers
|
||||
for ( auto& buffer : this->buffers ) lambda( buffer );
|
||||
// add per-graphics buffers
|
||||
for ( auto& buffer : graphic.buffers ) lambda( buffer );
|
||||
}
|
||||
void ext::vulkan::Pipeline::destroy() {
|
||||
if ( aliased ) return;
|
||||
|
||||
@ -1826,10 +1833,10 @@ const ext::vulkan::Pipeline& ext::vulkan::Graphic::getPipeline( const GraphicDes
|
||||
void ext::vulkan::Graphic::updatePipelines() {
|
||||
for ( auto pair : this->pipelines ) pair.second.update( *this );
|
||||
}
|
||||
void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, size_t pass, size_t draw ) const {
|
||||
return this->record( commandBuffer, descriptor, pass, draw );
|
||||
void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, size_t pass, size_t draw, size_t offset ) const {
|
||||
return this->record( commandBuffer, descriptor, pass, draw, offset );
|
||||
}
|
||||
void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass, size_t draw ) const {
|
||||
void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass, size_t draw, size_t offset ) const {
|
||||
if ( !process ) return;
|
||||
if ( !this->hasPipeline( descriptor ) ) {
|
||||
VK_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline ({} {})", descriptor.renderMode, descriptor.renderTarget);
|
||||
@ -1842,7 +1849,7 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
|
||||
return;
|
||||
}
|
||||
if ( !pipeline.metadata.process ) return;
|
||||
pipeline.record(*this, descriptor, commandBuffer, pass, draw);
|
||||
pipeline.record(*this, descriptor, commandBuffer, pass, draw, offset);
|
||||
|
||||
auto shaders = pipeline.getShaders( material.shaders );
|
||||
for ( auto* shader : shaders ) {
|
||||
|
||||
@ -221,9 +221,9 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderMode::bindGraphicDescriptor( c
|
||||
}
|
||||
|
||||
void ext::vulkan::RenderMode::createCommandBuffers() {
|
||||
this->execute = true;
|
||||
|
||||
uf::stl::vector<ext::vulkan::Graphic*> graphics;
|
||||
static thread_local uf::stl::vector<ext::vulkan::Graphic*> graphics;
|
||||
graphics.clear();
|
||||
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto/*&*/ graph = scene.getGraph();
|
||||
for ( auto entity : graph ) {
|
||||
@ -243,6 +243,7 @@ void ext::vulkan::RenderMode::createCommandBuffers() {
|
||||
this->mostRecentCommandPoolId = std::this_thread::get_id();
|
||||
this->rebuild = false;
|
||||
this->rerecord = false;
|
||||
this->execute = true;
|
||||
}
|
||||
ext::vulkan::RenderMode::commands_container_t& ext::vulkan::RenderMode::getCommands( std::thread::id id ) {
|
||||
bool exists = this->commands.has(id); //this->commands.count(id) > 0;
|
||||
@ -251,7 +252,7 @@ ext::vulkan::RenderMode::commands_container_t& ext::vulkan::RenderMode::getComma
|
||||
commands.resize( swapchain.buffers );
|
||||
|
||||
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
|
||||
device->getCommandPool(this->getType() == "Compute" ? QueueEnum::COMPUTE : QueueEnum::GRAPHICS),
|
||||
device->getCommandPool(this->queueEnum),
|
||||
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
static_cast<uint32_t>(commands.size())
|
||||
);
|
||||
@ -277,7 +278,6 @@ void ext::vulkan::RenderMode::cleanupAllCommands() {
|
||||
for ( auto& pair : container ) {
|
||||
if ( pair.second.empty() ) continue;
|
||||
|
||||
auto queueEnum = this->getType() == "Compute" ? QueueEnum::COMPUTE : QueueEnum::GRAPHICS;
|
||||
VkQueue queue = device->getQueue( queueEnum, pair.first );
|
||||
VkResult res = vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT );
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
@ -299,7 +299,6 @@ void ext::vulkan::RenderMode::cleanupCommands( std::thread::id id ) {
|
||||
if ( pair.first == id ) continue;
|
||||
if ( pair.second.empty() ) continue;
|
||||
|
||||
auto queueEnum = this->getType() == "Compute" ? QueueEnum::COMPUTE : QueueEnum::GRAPHICS;
|
||||
VkQueue queue = device->getQueue( queueEnum, pair.first );
|
||||
VkResult res = vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT );
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
@ -319,8 +318,6 @@ void ext::vulkan::RenderMode::createCommandBuffers( const uf::stl::vector<ext::v
|
||||
|
||||
}
|
||||
void ext::vulkan::RenderMode::bindPipelines() {
|
||||
this->execute = true;
|
||||
|
||||
uf::stl::vector<ext::vulkan::Graphic*> graphics;
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto/*&*/ graph = scene.getGraph();
|
||||
@ -333,6 +330,7 @@ void ext::vulkan::RenderMode::bindPipelines() {
|
||||
}
|
||||
this->synchronize();
|
||||
this->bindPipelines( graphics );
|
||||
this->execute = true;
|
||||
}
|
||||
void ext::vulkan::RenderMode::bindPipelines( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
|
||||
//lockMutex();
|
||||
@ -382,14 +380,16 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
|
||||
|
||||
// this->width = 0; //ext::vulkan::width;
|
||||
// this->height = 0; //ext::vulkan::height;
|
||||
if ( this->scale == 0 ) this->scale = 1;
|
||||
|
||||
if ( this->scale == 0 ) this->scale = 1;
|
||||
{
|
||||
if ( this->width > 0 ) renderTarget.width = this->width;
|
||||
if ( this->height > 0 ) renderTarget.height = this->height;
|
||||
if ( this->scale > 0 ) renderTarget.scale = this->scale;
|
||||
}
|
||||
|
||||
// set enum type
|
||||
this->queueEnum = this->getType() == "Compute" ? QueueEnum::COMPUTE : QueueEnum::GRAPHICS;
|
||||
|
||||
// Set sync objects
|
||||
{
|
||||
// Fences (Used to check draw command buffer completion)
|
||||
@ -403,7 +403,8 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
|
||||
VK_REGISTER_HANDLE( fence );
|
||||
}
|
||||
// Set sync objects
|
||||
{
|
||||
for ( auto i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
|
||||
auto& renderCompleteSemaphore = renderCompleteSemaphores.emplace_back();
|
||||
// Semaphores (Used for correct command ordering)
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
|
||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
@ -425,8 +426,10 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
|
||||
|
||||
void ext::vulkan::RenderMode::tick() {
|
||||
if ( ext::vulkan::states::resized || uf::renderer::states::rebuild || rebuild ) {
|
||||
if ( device ) vkDeviceWaitIdle(*device);
|
||||
cleanupAllCommands();
|
||||
}
|
||||
|
||||
this->synchronize();
|
||||
|
||||
if ( metadata.limiter.frequency > 0 ) {
|
||||
@ -445,26 +448,28 @@ void ext::vulkan::RenderMode::render() {
|
||||
}
|
||||
|
||||
void ext::vulkan::RenderMode::destroy() {
|
||||
if ( device ) vkDeviceWaitIdle(*device);
|
||||
this->synchronize();
|
||||
|
||||
renderTarget.destroy();
|
||||
|
||||
for ( auto& pair : this->commands.container() ) {
|
||||
if ( !pair.second.empty() ) {
|
||||
vkFreeCommandBuffers( *device, device->getCommandPool(this->getType() == "Compute" ? QueueEnum::COMPUTE : QueueEnum::GRAPHICS, pair.first), static_cast<uint32_t>(pair.second.size()), pair.second.data());
|
||||
vkFreeCommandBuffers( *device, device->getCommandPool(this->queueEnum, pair.first), static_cast<uint32_t>(pair.second.size()), pair.second.data());
|
||||
}
|
||||
pair.second.clear();
|
||||
}
|
||||
if ( renderCompleteSemaphore != VK_NULL_HANDLE ) {
|
||||
for ( auto& renderCompleteSemaphore : renderCompleteSemaphores ) {
|
||||
vkDestroySemaphore( *device, renderCompleteSemaphore, nullptr);
|
||||
VK_UNREGISTER_HANDLE( renderCompleteSemaphore );
|
||||
renderCompleteSemaphore = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
for ( auto& fence : fences ) {
|
||||
vkDestroyFence( *device, fence, nullptr);
|
||||
VK_UNREGISTER_HANDLE( fence );
|
||||
}
|
||||
|
||||
renderCompleteSemaphores.clear();
|
||||
fences.clear();
|
||||
blitter.destroy();
|
||||
ext::vulkan::Buffers::destroy();
|
||||
@ -474,9 +479,9 @@ void ext::vulkan::RenderMode::synchronize( uint64_t timeout ) {
|
||||
if ( fences.empty() ) return;
|
||||
lockMutex();
|
||||
|
||||
auto queueEnum = this->getType() == "Compute" ? QueueEnum::COMPUTE : QueueEnum::GRAPHICS;
|
||||
VkQueue queue = device->getQueue( queueEnum, this->mostRecentCommandPoolId );
|
||||
VkResult res = vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, timeout );
|
||||
// VkResult res = vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, timeout);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
|
||||
unlockMutex();
|
||||
|
||||
@ -90,10 +90,10 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
|
||||
for (size_t i = 0; i < commands.size(); ++i) {
|
||||
for (size_t frame = 0; frame < commands.size(); ++frame) {
|
||||
|
||||
auto& commandBuffer = commands[i];
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
|
||||
auto& commandBuffer = commands[frame];
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[frame];
|
||||
|
||||
|
||||
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
|
||||
@ -106,34 +106,33 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = 0;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[i].descriptor.layout;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[frame].descriptor.layout;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
// explicitly transfer queue-ownership
|
||||
if ( ext::vulkan::device.queueFamilyIndices.graphics != ext::vulkan::device.queueFamilyIndices.present ) {
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
} else {
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
} else {
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
}
|
||||
imageMemoryBarrier.image = renderTarget.attachments[i].image;
|
||||
imageMemoryBarrier.image = renderTarget.attachments[frame].image;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
renderTarget.attachments[i].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
renderTarget.attachments[frame].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
}
|
||||
|
||||
// pre-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) {
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_BEGIN, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[begin]" );
|
||||
commandBufferCallbacks[CALLBACK_BEGIN]( commandBuffer, i );
|
||||
}
|
||||
} );
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "renderPass[begin]" );
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
@ -151,17 +150,16 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass || blitter.descriptor.renderMode != this->getName() ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor; // bindGraphicDescriptor(blitter.descriptor, currentSubpass);
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("blitter[{}: {}]", layer->getName(), layer->getType()) );
|
||||
blitter.record(commandBuffer, descriptor);
|
||||
blitter.record(commandBuffer, descriptor, 0, 0, frame);
|
||||
}
|
||||
}
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "renderPass[end]" );
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
|
||||
// post-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) {
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
|
||||
commandBufferCallbacks[CALLBACK_END]( commandBuffer, i );
|
||||
}
|
||||
} );
|
||||
|
||||
// need to transfer it back, if they differ
|
||||
if ( ext::vulkan::device.queueFamilyIndices.graphics != ext::vulkan::device.queueFamilyIndices.present ) {
|
||||
@ -169,18 +167,18 @@ void ext::vulkan::BaseRenderMode::createCommandBuffers( const uf::stl::vector<ex
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[i].descriptor.layout;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[frame].descriptor.layout;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.image = renderTarget.attachments[i].image;
|
||||
imageMemoryBarrier.image = renderTarget.attachments[frame].image;
|
||||
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
renderTarget.attachments[i].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
renderTarget.attachments[frame].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
@ -205,10 +203,13 @@ void ext::vulkan::BaseRenderMode::render() {
|
||||
// if ( ext::vulkan::renderModes.size() > 1 ) return;
|
||||
// if ( ext::vulkan::renderModes.back() != this ) return;
|
||||
|
||||
if ( this->commands.container().empty() ) return;
|
||||
|
||||
//lockMutex( this->mostRecentCommandPoolId );
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
// Get next image in the swap chain (back/front buffer)
|
||||
VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphore));
|
||||
VK_CHECK_RESULT(swapchain.acquireNextImage(&states::currentBuffer, swapchain.presentCompleteSemaphores[0]));
|
||||
|
||||
// Use a fence to wait until the command buffer has finished execution before using it again
|
||||
VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
|
||||
@ -219,32 +220,39 @@ void ext::vulkan::BaseRenderMode::render() {
|
||||
// The submit info structure specifices a command buffer queue submission batch
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[0]; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer]; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
// Submit to the graphics queue passing a wait fence
|
||||
// VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
|
||||
#if 1
|
||||
VK_CHECK_RESULT(vkQueueSubmit( device->getQueue( QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
|
||||
#else
|
||||
{
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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->getQueue( QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphore));
|
||||
// VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( QueueEnum::PRESENT )));
|
||||
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), states::currentBuffer, renderCompleteSemaphores[states::currentBuffer]));
|
||||
|
||||
#if 1
|
||||
//VK_CHECK_RESULT(vkQueueWaitIdle(device->getQueue( QueueEnum::PRESENT )));
|
||||
#else
|
||||
{
|
||||
VkQueue queue = device->getQueue( QueueEnum::PRESENT );
|
||||
VkResult res = vkQueueWaitIdle(device->getQueue( QueueEnum::PRESENT ));
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
}
|
||||
#endif
|
||||
|
||||
this->executed = true;
|
||||
|
||||
@ -276,7 +284,7 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
// uint32_t height = windowSize.y; //this->height > 0 ? this->height : windowSize.y;
|
||||
|
||||
size_t attachmentIndex = 0;
|
||||
for ( size_t i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
|
||||
for ( size_t frame = 0; frame < ext::vulkan::swapchain.buffers; ++frame ) {
|
||||
VkImageViewCreateInfo colorAttachmentView = {};
|
||||
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
colorAttachmentView.pNext = NULL;
|
||||
@ -294,20 +302,20 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
colorAttachmentView.subresourceRange.layerCount = 1;
|
||||
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
colorAttachmentView.flags = 0;
|
||||
colorAttachmentView.image = images[i];
|
||||
colorAttachmentView.image = images[frame];
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[i].view));
|
||||
VK_REGISTER_HANDLE( renderTarget.attachments[i].view );
|
||||
VK_CHECK_RESULT(vkCreateImageView( device, &colorAttachmentView, nullptr, &renderTarget.attachments[frame].view));
|
||||
VK_REGISTER_HANDLE( renderTarget.attachments[frame].view );
|
||||
|
||||
renderTarget.attachments[i].descriptor.format = ext::vulkan::settings::formats::color;
|
||||
// renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
renderTarget.attachments[i].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
renderTarget.attachments[i].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
renderTarget.attachments[i].descriptor.aliased = true;
|
||||
renderTarget.attachments[i].image = images[i];
|
||||
renderTarget.attachments[i].mem = VK_NULL_HANDLE;
|
||||
renderTarget.attachments[frame].descriptor.format = ext::vulkan::settings::formats::color;
|
||||
// renderTarget.attachments[frame].descriptor.layout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
renderTarget.attachments[frame].descriptor.layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
renderTarget.attachments[frame].descriptor.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
renderTarget.attachments[frame].descriptor.aliased = true;
|
||||
renderTarget.attachments[frame].image = images[frame];
|
||||
renderTarget.attachments[frame].mem = VK_NULL_HANDLE;
|
||||
|
||||
metadata.attachments["color["+std::to_string((int) i)+"]"] = attachmentIndex++;
|
||||
metadata.attachments["color["+std::to_string((int) frame)+"]"] = attachmentIndex++;
|
||||
}
|
||||
{
|
||||
// Create depth
|
||||
@ -523,10 +531,10 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
{
|
||||
// Create a frame buffer for every image in the swapchain
|
||||
renderTarget.framebuffers.resize(images.size());
|
||||
for (size_t i = 0; i < renderTarget.framebuffers.size(); i++)
|
||||
for (size_t frame = 0; frame < renderTarget.framebuffers.size(); frame++)
|
||||
{
|
||||
std::array<VkImageView, 2> attachments;
|
||||
attachments[0] = renderTarget.attachments[i].view; // Color attachment is the view of the swapchain image
|
||||
attachments[0] = renderTarget.attachments[frame].view; // Color attachment is the view of the swapchain image
|
||||
attachments[1] = renderTarget.attachments[metadata.attachments["depth"]].view; // Depth/Stencil attachment is the same for all frame buffers
|
||||
|
||||
VkFramebufferCreateInfo frameBufferCreateInfo = {};
|
||||
@ -539,32 +547,32 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
frameBufferCreateInfo.height = height;
|
||||
frameBufferCreateInfo.layers = 1;
|
||||
// Create the framebuffer
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &renderTarget.framebuffers[i]));
|
||||
VK_REGISTER_HANDLE(renderTarget.framebuffers[i]);
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer( device, &frameBufferCreateInfo, nullptr, &renderTarget.framebuffers[frame]));
|
||||
VK_REGISTER_HANDLE(renderTarget.framebuffers[frame]);
|
||||
}
|
||||
|
||||
}
|
||||
#if 0
|
||||
if ( true ) {
|
||||
auto commandBuffer = device.fetchCommandBuffer(uf::renderer::QueueEnum::TRANSFER);
|
||||
for ( size_t i = 0; i < images.size(); ++i ) {
|
||||
for ( size_t frame = 0; frame < images.size(); ++frame ) {
|
||||
VkImageMemoryBarrier imageMemoryBarrier = {};
|
||||
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
imageMemoryBarrier.srcAccessMask = 0;
|
||||
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[i].descriptor.layout;
|
||||
imageMemoryBarrier.oldLayout = renderTarget.attachments[frame].descriptor.layout;
|
||||
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.present;
|
||||
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics;
|
||||
|
||||
imageMemoryBarrier.image = renderTarget.attachments[i].image;
|
||||
imageMemoryBarrier.image = renderTarget.attachments[frame].image;
|
||||
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
|
||||
imageMemoryBarrier.subresourceRange.levelCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
imageMemoryBarrier.subresourceRange.layerCount = 1;
|
||||
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
renderTarget.attachments[i].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
renderTarget.attachments[frame].descriptor.layout = imageMemoryBarrier.newLayout;
|
||||
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
}
|
||||
@ -597,15 +605,16 @@ void ext::vulkan::BaseRenderMode::initialize( Device& device ) {
|
||||
renderTarget.initialize( device );
|
||||
*/
|
||||
// Set sync objects
|
||||
{
|
||||
for ( auto i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
|
||||
auto& presentCompleteSemaphore = swapchain.presentCompleteSemaphores.emplace_back();
|
||||
// Semaphores (Used for correct command ordering)
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
|
||||
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
semaphoreCreateInfo.pNext = nullptr;
|
||||
|
||||
// Semaphore used to ensures that image presentation is complete before starting to submit again
|
||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &swapchain.presentCompleteSemaphore));
|
||||
VK_REGISTER_HANDLE(swapchain.presentCompleteSemaphore);
|
||||
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &presentCompleteSemaphore));
|
||||
VK_REGISTER_HANDLE(presentCompleteSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
@ -616,11 +625,11 @@ void ext::vulkan::BaseRenderMode::destroy() {
|
||||
renderTarget.renderPass = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
for ( uint32_t i = 0; i < renderTarget.framebuffers.size(); i++ ) {
|
||||
if ( renderTarget.framebuffers[i] != VK_NULL_HANDLE ) {
|
||||
vkDestroyFramebuffer( *device, renderTarget.framebuffers[i], nullptr );
|
||||
VK_UNREGISTER_HANDLE( renderTarget.framebuffers[i] );
|
||||
renderTarget.framebuffers[i] = VK_NULL_HANDLE;
|
||||
for ( uint32_t frame = 0; frame < renderTarget.framebuffers.size(); frame++ ) {
|
||||
if ( renderTarget.framebuffers[frame] != VK_NULL_HANDLE ) {
|
||||
vkDestroyFramebuffer( *device, renderTarget.framebuffers[frame], nullptr );
|
||||
VK_UNREGISTER_HANDLE( renderTarget.framebuffers[frame] );
|
||||
renderTarget.framebuffers[frame] = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
for ( auto& attachment : renderTarget.attachments ) {
|
||||
@ -650,10 +659,11 @@ void ext::vulkan::BaseRenderMode::destroy() {
|
||||
|
||||
ext::vulkan::RenderMode::destroy();
|
||||
|
||||
if ( swapchain.presentCompleteSemaphore != VK_NULL_HANDLE ) {
|
||||
vkDestroySemaphore( *device, swapchain.presentCompleteSemaphore, nullptr);
|
||||
VK_UNREGISTER_HANDLE( swapchain.presentCompleteSemaphore );
|
||||
for ( auto& presentCompleteSemaphore : swapchain.presentCompleteSemaphores ) {
|
||||
vkDestroySemaphore( *device, presentCompleteSemaphore, nullptr);
|
||||
VK_UNREGISTER_HANDLE( presentCompleteSemaphore );
|
||||
}
|
||||
swapchain.presentCompleteSemaphores.clear();
|
||||
}
|
||||
|
||||
ext::vulkan::GraphicDescriptor ext::vulkan::BaseRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
|
||||
|
||||
@ -610,26 +610,30 @@ VkSubmitInfo ext::vulkan::DeferredRenderMode::queue() {
|
||||
// The submit info structure specifices a command buffer queue submission batch
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphore; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphore; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[states::currentBuffer]; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer]; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
return submitInfo;
|
||||
}
|
||||
void ext::vulkan::DeferredRenderMode::render() {
|
||||
// if ( this->executed ) return;
|
||||
if ( commandBufferCallbacks.count(EXECUTE_BEGIN) > 0 ) commandBufferCallbacks[EXECUTE_BEGIN]( VkCommandBuffer{}, 0 );
|
||||
|
||||
//lockMutex( this->mostRecentCommandPoolId );
|
||||
if ( this->commands.container().empty() ) return;
|
||||
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_BEGIN, VkCommandBuffer{}, 0, {} );
|
||||
// Submit commands
|
||||
// Use a fence to ensure that command buffer has finished executing before using it again
|
||||
/*
|
||||
VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT ));
|
||||
VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] ));
|
||||
*/
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
@ -643,9 +647,9 @@ void ext::vulkan::DeferredRenderMode::render() {
|
||||
|
||||
// VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE/*fences[states::currentBuffer]*/);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
if ( commandBufferCallbacks.count(EXECUTE_END) > 0 ) commandBufferCallbacks[EXECUTE_END]( VkCommandBuffer{}, 0 );
|
||||
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_END, VkCommandBuffer{}, 0, {} );
|
||||
|
||||
this->executed = true;
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
@ -701,8 +705,8 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
}
|
||||
}
|
||||
bool shouldRecord = true; // ( settings::pipelines::rt && !uf::config["engine"]["scenes"]["rt"]["full"].as<bool>() ) || !settings::pipelines::rt;
|
||||
for (size_t i = 0; i < commands.size(); ++i) {
|
||||
auto commandBuffer = commands[i];
|
||||
for (size_t frame = 0; frame < commands.size(); ++frame) {
|
||||
auto commandBuffer = commands[frame];
|
||||
VK_CHECK_RESULT( vkBeginCommandBuffer(commandBuffer, &cmdBufInfo) );
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "begin" );
|
||||
|
||||
@ -718,7 +722,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
renderPassBeginInfo.clearValueCount = clearValues.size();
|
||||
renderPassBeginInfo.pClearValues = &clearValues[0];
|
||||
renderPassBeginInfo.renderPass = renderTarget.renderPass;
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[frame];
|
||||
|
||||
// Update dynamic viewport state
|
||||
VkViewport viewport = {};
|
||||
@ -780,15 +784,14 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
|
||||
}
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("graphic[{}]", pipeline) );
|
||||
graphic->record( commandBuffer, descriptor, 0, metadata.eyes );
|
||||
graphic->record( commandBuffer, descriptor, 0, metadata.eyes, frame );
|
||||
}
|
||||
}
|
||||
|
||||
// pre-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) {
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_BEGIN, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[begin]" );
|
||||
commandBufferCallbacks[CALLBACK_BEGIN]( commandBuffer, i );
|
||||
}
|
||||
} );
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "renderPass[begin]" ) ;
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
@ -803,7 +806,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
if ( graphic->descriptor.renderMode != this->getName() ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentSubpass);
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("graphic[{}]", currentDraw) );
|
||||
graphic->record( commandBuffer, descriptor, eye, currentDraw++ );
|
||||
graphic->record( commandBuffer, descriptor, eye, currentDraw++, frame );
|
||||
}
|
||||
if ( eye + 1 < metadata.eyes ) {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "nextSubpass" );
|
||||
@ -821,7 +824,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
descriptor.subpass = currentSubpass;
|
||||
descriptor.bind.point = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "deferred" );
|
||||
blitter.record(commandBuffer, descriptor, eye, currentDraw++);
|
||||
blitter.record(commandBuffer, descriptor, eye, currentDraw++, frame);
|
||||
}
|
||||
if ( eye + 1 < metadata.eyes ) {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "nextSubpass" );
|
||||
@ -849,7 +852,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
|
||||
// dispatch compute shader
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "deferred" );
|
||||
blitter.record(commandBuffer, descriptor, 0, 0);
|
||||
blitter.record(commandBuffer, descriptor, 0, 0, frame);
|
||||
|
||||
// transition attachments back to shader read layouts
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
@ -877,15 +880,15 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
auto& attachmentScratch = this->getAttachment("scratch"); // pingpong
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[1]" );
|
||||
blitter.record(commandBuffer, descriptor, 0, 1);
|
||||
blitter.record( commandBuffer, descriptor, 0, 1 );
|
||||
cmdImageBarrier( commandBuffer, attachmentScratch.image, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL );
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[2]" );
|
||||
blitter.record(commandBuffer, descriptor, 0, 2);
|
||||
blitter.record( commandBuffer, descriptor, 0, 2 );
|
||||
cmdImageBarrier( commandBuffer, attachmentBright.image, VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL );
|
||||
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "bloom[3]" );
|
||||
blitter.record(commandBuffer, descriptor, 0, 3);
|
||||
blitter.record( commandBuffer, descriptor, 0, 3 );
|
||||
|
||||
// transition attachments back to shader read layouts
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "setImageLayout" );
|
||||
@ -934,7 +937,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
if ( descriptor.bind.width < 1 ) descriptor.bind.width = 1;
|
||||
if ( descriptor.bind.height < 1 ) descriptor.bind.height = 1;
|
||||
|
||||
blitter.record(commandBuffer, descriptor, 0, i);
|
||||
blitter.record(commandBuffer, descriptor, 0, i, frame);
|
||||
vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_FLAGS_NONE, 1, &memoryBarrier, 0, NULL, 0, NULL );
|
||||
}
|
||||
|
||||
@ -945,10 +948,9 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
}
|
||||
#endif
|
||||
// post-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) {
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
|
||||
commandBufferCallbacks[CALLBACK_END]( commandBuffer, i );
|
||||
}
|
||||
} );
|
||||
|
||||
#if 0
|
||||
if ( this->hasAttachment("depth") ) {
|
||||
|
||||
@ -419,15 +419,19 @@ void ext::vulkan::RenderTargetRenderMode::destroy() {
|
||||
|
||||
void ext::vulkan::RenderTargetRenderMode::render() {
|
||||
// if ( this->executed ) return;
|
||||
|
||||
if ( commandBufferCallbacks.count(EXECUTE_BEGIN) > 0 ) commandBufferCallbacks[EXECUTE_BEGIN]( VkCommandBuffer{}, 0 );
|
||||
if ( this->commands.container().empty() ) return;
|
||||
|
||||
//lockMutex( this->mostRecentCommandPoolId );
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_BEGIN, VkCommandBuffer{}, 0, {} );
|
||||
|
||||
// Submit commands
|
||||
// Use a fence to ensure that command buffer has finished executing before using it again
|
||||
/*
|
||||
VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT ));
|
||||
VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] ));
|
||||
*/
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
@ -441,10 +445,9 @@ void ext::vulkan::RenderTargetRenderMode::render() {
|
||||
|
||||
// VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
|
||||
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
|
||||
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE/*fences[states::currentBuffer]*/);
|
||||
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
|
||||
|
||||
if ( commandBufferCallbacks.count(EXECUTE_END) > 0 ) commandBufferCallbacks[EXECUTE_END]( VkCommandBuffer{}, 0 );
|
||||
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_END, VkCommandBuffer{}, 0, {} );
|
||||
|
||||
this->executed = true;
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
@ -481,8 +484,8 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
}
|
||||
|
||||
auto& commands = getCommands();
|
||||
for (size_t i = 0; i < commands.size(); ++i) {
|
||||
auto& commandBuffer = commands[i];
|
||||
for (size_t frame = 0; frame < commands.size(); ++frame) {
|
||||
auto& commandBuffer = commands[frame];
|
||||
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "begin" );
|
||||
{
|
||||
@ -497,7 +500,7 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
renderPassBeginInfo.clearValueCount = clearValues.size();
|
||||
renderPassBeginInfo.pClearValues = &clearValues[0];
|
||||
renderPassBeginInfo.renderPass = renderTarget.renderPass;
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[i];
|
||||
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[frame];
|
||||
|
||||
// Update dynamic viewport state
|
||||
VkViewport viewport = {};
|
||||
@ -517,7 +520,7 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
size_t currentPass = 0;
|
||||
|
||||
//
|
||||
// this->pipelineBarrier( commands[i], 1 );
|
||||
// this->pipelineBarrier( commands[frame], 1 );
|
||||
|
||||
// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||
// VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
|
||||
@ -540,10 +543,9 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
#endif
|
||||
|
||||
// pre-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) {
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_BEGIN, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[begin]" );
|
||||
commandBufferCallbacks[CALLBACK_BEGIN]( commandBuffer, i );
|
||||
}
|
||||
} );
|
||||
|
||||
if ( this->getName() == "Compute" ) {
|
||||
for ( auto graphic : graphics ) {
|
||||
@ -573,7 +575,7 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
UF_MSG_DEBUG("Aux pipeline: {}", pipeline);
|
||||
}
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("graphic[{}]", pipeline) );
|
||||
graphic->record( commandBuffer, descriptor, 0, metadata.type == uf::renderer::settings::pipelines::names::vxgi ? 0 : MIN(subpasses,6) );
|
||||
graphic->record( commandBuffer, descriptor, 0, metadata.type == uf::renderer::settings::pipelines::names::vxgi ? 0 : MIN(subpasses,6), frame );
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,12 +589,13 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
if ( graphic->descriptor.renderMode != this->getTarget() ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(graphic->descriptor, currentPass);
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("graphic[{}]", currentDraw) );
|
||||
graphic->record( commandBuffer, descriptor, currentPass, currentDraw++ );
|
||||
graphic->record( commandBuffer, descriptor, currentPass, currentDraw++, frame );
|
||||
}
|
||||
if ( commandBufferCallbacks.count( currentPass ) > 0 ) {
|
||||
commandBufferCallbacks[currentPass]( commandBuffer, i );
|
||||
|
||||
VK_COMMAND_BUFFER_CALLBACK( currentPass, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("callback[{}]", currentPass) );
|
||||
}
|
||||
} );
|
||||
|
||||
if ( currentPass + 1 < subpasses ) {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "nextSubpass" );
|
||||
vkCmdNextSubpass(commandBuffer, VK_SUBPASS_CONTENTS_INLINE);
|
||||
@ -604,12 +607,11 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
|
||||
|
||||
|
||||
// post-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) {
|
||||
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
|
||||
commandBufferCallbacks[CALLBACK_END]( commandBuffer, i );
|
||||
}
|
||||
} );
|
||||
|
||||
// this->pipelineBarrier( commands[i], 1 );
|
||||
// this->pipelineBarrier( commands[frame], 1 );
|
||||
}
|
||||
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
|
||||
|
||||
@ -484,18 +484,17 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
etype,
|
||||
};
|
||||
} break;
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: {
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: {
|
||||
size_t bufferSize = comp.get_declared_struct_size(base_type);
|
||||
if ( bufferSize <= 0 ) break;
|
||||
if ( bufferSize > device.properties.limits.maxUniformBufferRange ) {
|
||||
VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer length of " << bufferSize << " for shader " << filename);
|
||||
bufferSize = device.properties.limits.maxUniformBufferRange;
|
||||
}
|
||||
size_t misalignment = bufferSize % device.properties.limits.minStorageBufferOffsetAlignment;
|
||||
if ( misalignment != 0 ) {
|
||||
VK_DEBUG_VALIDATION_MESSAGE("Invalid uniform buffer alignment of " << misalignment << " for shader " << filename << ", correcting...");
|
||||
bufferSize += misalignment;
|
||||
}
|
||||
|
||||
bufferSize = ALIGNED_SIZE( bufferSize, device.properties.limits.minUniformBufferOffsetAlignment );
|
||||
|
||||
{
|
||||
VK_DEBUG_VALIDATION_MESSAGE("Uniform size of " << bufferSize << " for shader " << filename);
|
||||
// auto& uniform = uniforms.emplace_back();
|
||||
@ -518,14 +517,20 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
binding,
|
||||
bufferSize,
|
||||
};
|
||||
|
||||
if ( descriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC ) {
|
||||
metadata.dynamicRanges.emplace_back( bufferSize );
|
||||
}
|
||||
} break;
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER: {
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
|
||||
// generate definition to JSON
|
||||
#if UF_SHADER_PARSE_AS_JSON
|
||||
{
|
||||
metadata.json["definitions"]["storage"][name]["name"] = name;
|
||||
metadata.json["definitions"]["storage"][name]["index"] = index;
|
||||
metadata.json["definitions"]["storage"][name]["binding"] = binding;
|
||||
// metadata.json["definitions"]["storage"][name]["size"] = bufferSize;
|
||||
metadata.json["definitions"]["storage"][name]["members"] = parseMembers(resource.type_id);
|
||||
}
|
||||
#endif
|
||||
@ -567,7 +572,11 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
LOOP_RESOURCES( storage_images, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE );
|
||||
LOOP_RESOURCES( separate_samplers, VK_DESCRIPTOR_TYPE_SAMPLER );
|
||||
LOOP_RESOURCES( subpass_inputs, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT );
|
||||
#if VK_UBO_USE_N_BUFFERS
|
||||
LOOP_RESOURCES( uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC );
|
||||
#else
|
||||
LOOP_RESOURCES( uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER );
|
||||
#endif
|
||||
LOOP_RESOURCES( storage_buffers, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER );
|
||||
LOOP_RESOURCES( acceleration_structures, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR );
|
||||
#undef LOOP_RESOURCES
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
#include <uf/ext/vulkan/initializers.h>
|
||||
#include <uf/utils/window/window.h>
|
||||
|
||||
VkResult ext::vulkan::Swapchain::acquireNextImage( uint32_t* imageIndex, VkSemaphore presentCompleteSemaphore ) {
|
||||
VkResult ext::vulkan::Swapchain::acquireNextImage( uint32_t* imageIndex, VkSemaphore presentCompleteSemaphore, VkFence acquireFence ) {
|
||||
// By setting timeout to UINT64_MAX we will always wait until the next image has been acquired or an actual error is thrown
|
||||
// With that we don't have to handle VK_NOT_READY
|
||||
return vkAcquireNextImageKHR( *device, swapChain, VK_DEFAULT_FENCE_TIMEOUT, presentCompleteSemaphore, (VkFence) nullptr, imageIndex );
|
||||
return vkAcquireNextImageKHR( *device, swapChain, VK_DEFAULT_FENCE_TIMEOUT, presentCompleteSemaphore, acquireFence, imageIndex );
|
||||
}
|
||||
|
||||
VkResult ext::vulkan::Swapchain::queuePresent( VkQueue queue, uint32_t imageIndex, VkSemaphore waitSemaphore ) {
|
||||
|
||||
@ -515,7 +515,7 @@ void ext::vulkan::Texture::fromBuffers(
|
||||
vkGetPhysicalDeviceFormatProperties(device.physicalDevice, format, &formatProperties);
|
||||
if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) {
|
||||
this->mips = 1;
|
||||
VK_VALIDATION_MESSAGE("Texture image format {} does not support linear blitting", format);
|
||||
// VK_VALIDATION_MESSAGE("Texture image format {} does not support linear blitting", format);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -476,7 +476,7 @@ void ext::vulkan::initialize( bool soft ) {
|
||||
|
||||
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
|
||||
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
|
||||
tasks.queue([&]{
|
||||
tasks.queue([renderMode]{
|
||||
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
|
||||
renderMode->createCommandBuffers();
|
||||
});
|
||||
@ -523,11 +523,11 @@ void ext::vulkan::tick() {
|
||||
|
||||
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
|
||||
for ( auto& renderMode : renderModes ) { if ( !renderMode || (renderMode->executed && !renderMode->execute) ) continue;
|
||||
if ( ext::vulkan::states::rebuild || renderMode->rebuild ) tasks.queue([&]{
|
||||
if ( ext::vulkan::states::rebuild || renderMode->rebuild ) tasks.queue([renderMode]{
|
||||
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
|
||||
renderMode->createCommandBuffers();
|
||||
});
|
||||
else if ( renderMode->rerecord ) tasks.queue([&]{
|
||||
else if ( renderMode->rerecord ) tasks.queue([renderMode]{
|
||||
renderMode->createCommandBuffers();
|
||||
});
|
||||
}
|
||||
@ -597,9 +597,11 @@ void ext::vulkan::render() {
|
||||
else submitsGraphics.emplace_back(submitInfo);
|
||||
renderMode->executed = true;
|
||||
|
||||
// tasks.queue([&]{
|
||||
// tasks.queue([renderMode]{
|
||||
ext::vulkan::setCurrentRenderMode(renderMode);
|
||||
uf::scene::render();
|
||||
if ( renderMode->getType() != "Swapchain" ) {
|
||||
uf::scene::render();
|
||||
}
|
||||
ext::vulkan::setCurrentRenderMode(NULL);
|
||||
// });
|
||||
}
|
||||
@ -617,9 +619,11 @@ void ext::vulkan::render() {
|
||||
// stuff we can't batch
|
||||
for ( auto renderMode : specialRenderModes ) {
|
||||
ext::vulkan::setCurrentRenderMode(renderMode);
|
||||
uf::scene::render();
|
||||
if ( renderMode->getType() != "Swapchain" ) {
|
||||
uf::scene::render();
|
||||
}
|
||||
#if UF_USE_FFX_FSR
|
||||
if ( renderMode->getName() == "Swapchain" && settings::pipelines::fsr && ext::fsr::initialized ) {
|
||||
if ( renderMode->getType() == "Swapchain" && settings::pipelines::fsr && ext::fsr::initialized ) {
|
||||
ext::fsr::tick();
|
||||
ext::fsr::render();
|
||||
}
|
||||
@ -637,15 +641,16 @@ void ext::vulkan::render() {
|
||||
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue;
|
||||
|
||||
#if UF_USE_FFX_FSR
|
||||
if ( renderMode->getName() == "Swapchain" && settings::pipelines::fsr && ext::fsr::initialized ) {
|
||||
if ( renderMode->getType() == "Swapchain" && settings::pipelines::fsr && ext::fsr::initialized ) {
|
||||
ext::fsr::tick();
|
||||
ext::fsr::render();
|
||||
}
|
||||
#endif
|
||||
|
||||
ext::vulkan::setCurrentRenderMode(renderMode);
|
||||
uf::graph::render();
|
||||
uf::scene::render();
|
||||
if ( renderMode->getType() != "Swapchain" ) {
|
||||
uf::scene::render();
|
||||
}
|
||||
renderMode->render();
|
||||
ext::vulkan::setCurrentRenderMode(NULL);
|
||||
|
||||
|
||||
@ -22,8 +22,6 @@ void uf::physics::tick( ) {
|
||||
return uf::physics::tick( uf::scene::getCurrentScene() );
|
||||
}
|
||||
void uf::physics::tick( uf::Object& scene ) {
|
||||
++uf::physics::time::frame;
|
||||
|
||||
uf::physics::time::previous = uf::physics::time::current;
|
||||
uf::physics::time::current = uf::physics::time::timer.elapsed();
|
||||
|
||||
@ -31,7 +29,12 @@ void uf::physics::tick( uf::Object& scene ) {
|
||||
if ( uf::physics::time::delta > uf::physics::time::clamp ) {
|
||||
uf::physics::time::delta = uf::physics::time::clamp;
|
||||
}
|
||||
uf::physics::impl::tick( scene, uf::physics::time::delta );
|
||||
|
||||
if ( uf::physics::impl::async ) {
|
||||
uf::thread::queue( "Physics", [&](){ uf::physics::impl::tick( scene, uf::physics::time::delta ); });
|
||||
} else {
|
||||
uf::physics::impl::tick( scene, uf::physics::time::delta );
|
||||
}
|
||||
}
|
||||
void uf::physics::terminate( ) {
|
||||
return uf::physics::terminate( uf::scene::getCurrentScene() );
|
||||
|
||||
@ -77,7 +77,6 @@ namespace {
|
||||
|
||||
constexpr auto numBins = 16;
|
||||
static thread_local Bin bins[numBins];
|
||||
for ( auto i = 0; i < numBins; i++ ) bins[i].count = 0;
|
||||
|
||||
auto extent = bound.max - bound.min;
|
||||
auto bestAxis = -1, bestSplit = -1;
|
||||
@ -85,6 +84,10 @@ namespace {
|
||||
|
||||
for ( auto axis = 0; axis < 3; ++axis ) {
|
||||
if ( extent[axis] < EPS(1e-6f) ) continue;
|
||||
for ( auto i = 0; i < numBins; i++ ) {
|
||||
bins[i].count = 0;
|
||||
bins[i].bounds = {};
|
||||
}
|
||||
|
||||
float minC = bound.min[axis];
|
||||
float maxC = bound.max[axis];
|
||||
@ -203,10 +206,10 @@ namespace {
|
||||
if ( bvh.indices.empty() ) return; // inserted nothing
|
||||
|
||||
// recursively build BVH from indices
|
||||
if ( ::useBvhSahBodies ) ::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
if ( uf::physics::impl::settings.useBvhSahBodies ) ::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
else ::buildBVHNode( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
// flatten if requested
|
||||
if ( ::flattenBvhBodies ) ::flattenBVH( bvh, 0 );
|
||||
if ( uf::physics::impl::settings.flattenBvhBodies ) ::flattenBVH( bvh, 0 );
|
||||
|
||||
// mark as clean
|
||||
bvh.dirty = false;
|
||||
@ -245,10 +248,10 @@ namespace {
|
||||
}
|
||||
|
||||
// recursively build BVH from indices
|
||||
if ( ::useBvhSahMeshes ) ::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
if ( uf::physics::impl::settings.useBvhSahMeshes ) ::buildBVHNode_SAH( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
else ::buildBVHNode( bvh, bounds, 0, bvh.indices.size(), capacity );
|
||||
// flatten if requested
|
||||
if ( ::flattenBvhMeshes ) ::flattenBVH( bvh, 0 );
|
||||
if ( uf::physics::impl::settings.flattenBvhMeshes ) ::flattenBVH( bvh, 0 );
|
||||
|
||||
// mark as clean
|
||||
bvh.dirty = false;
|
||||
@ -316,7 +319,7 @@ namespace {
|
||||
|
||||
// update leaf bounds
|
||||
uf::stl::vector<pod::BVH::index_t> leaves;
|
||||
leaves.reserve(::reserveCount);
|
||||
leaves.reserve(uf::physics::impl::settings.reserveCount);
|
||||
for ( auto i = 0; i < bvh.nodes.size(); i++ ) {
|
||||
if ( bvh.nodes[i].getCount() == 0 ) continue;
|
||||
leaves.emplace_back(i);
|
||||
@ -333,7 +336,7 @@ namespace {
|
||||
}
|
||||
|
||||
// update internal nodes bottom-up
|
||||
for ( pod::BVH::index_t i = (pod::BVH::index_t) bvh.nodes.size() - 1; i >= 0; i-- ) {
|
||||
for ( int64_t i = (int64_t) bvh.nodes.size() - 1; i >= 0; i-- ) {
|
||||
auto& node = bvh.nodes[i];
|
||||
auto& bound = bvh.bounds[i];
|
||||
// internal node
|
||||
@ -534,7 +537,7 @@ namespace {
|
||||
if ( !bvh.flattened.empty() ) return ::queryFlatOverlaps( bvh, outPairs );
|
||||
|
||||
if ( bvh.nodes.empty() ) return;
|
||||
outPairs.reserve(::reserveCount);
|
||||
outPairs.reserve(uf::physics::impl::settings.reserveCount);
|
||||
::traverseBVH( bvh, 0, outPairs );
|
||||
}
|
||||
|
||||
@ -542,7 +545,7 @@ namespace {
|
||||
if ( !bvhA.flattened.empty() && !bvhB.flattened.empty() ) return ::queryFlatOverlaps( bvhA, bvhB, outPairs );
|
||||
|
||||
if ( bvhA.nodes.empty() || bvhB.nodes.empty() ) return;
|
||||
outPairs.reserve(::reserveCount);
|
||||
outPairs.reserve(uf::physics::impl::settings.reserveCount);
|
||||
::traverseNodePair(bvhA, 0, bvhB, 0, outPairs);
|
||||
}
|
||||
}
|
||||
@ -554,7 +557,7 @@ namespace {
|
||||
|
||||
if ( !bvh.flattened.empty() ) return ::queryFlatBVH( bvh, bounds, outIndices );
|
||||
|
||||
outIndices.reserve(::reserveCount);
|
||||
outIndices.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
static thread_local uf::stl::stack<pod::BVH::index_t> stack;
|
||||
//stack.clear(); // there is no stack.clear(), and the stack should already be cleared by the end of this function
|
||||
@ -581,7 +584,7 @@ namespace {
|
||||
void queryBVH( const pod::BVH& bvh, const pod::AABB& bounds, uf::stl::vector<pod::BVH::index_t>& outIndices, pod::BVH::index_t nodeID ) {
|
||||
if ( !bvh.flattened.empty() ) return ::queryFlatBVH( bvh, bounds, outIndices );
|
||||
|
||||
if ( nodeID == 0 ) outIndices.reserve(::reserveCount);
|
||||
if ( nodeID == 0 ) outIndices.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
const auto& node = bvh.nodes[nodeID];
|
||||
if ( node.isAsleep() || !::aabbOverlap( bounds, bvh.bounds[nodeID] ) ) return;
|
||||
@ -601,7 +604,7 @@ namespace {
|
||||
if ( !bvh.flattened.empty() ) return ::queryFlatBVH( bvh, ray, outIndices, maxDist );
|
||||
|
||||
if ( bvh.nodes.empty() ) return;
|
||||
outIndices.reserve(::reserveCount);
|
||||
outIndices.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
static thread_local uf::stl::stack<pod::BVH::index_t> stack;
|
||||
//stack.clear(); // there is no stack.clear(), and the stack should already be cleared by the end of this function
|
||||
@ -627,7 +630,7 @@ namespace {
|
||||
void queryBVH( const pod::BVH& bvh, const pod::Ray& ray, uf::stl::vector<pod::BVH::index_t>& outIndices, pod::BVH::index_t nodeID, float maxDist ) {
|
||||
if ( !bvh.flattened.empty() ) return ::queryFlatBVH( bvh, ray, outIndices, maxDist );
|
||||
|
||||
if ( nodeID == 0 ) outIndices.reserve(::reserveCount);
|
||||
if ( nodeID == 0 ) outIndices.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
const auto& node = bvh.nodes[nodeID];
|
||||
float tMin, tMax;
|
||||
@ -649,63 +652,81 @@ namespace {
|
||||
namespace {
|
||||
void queryFlatOverlaps( const pod::BVH& bvh, pod::BVH::pairs_t& outPairs ) {
|
||||
auto& nodes = bvh.flattened;
|
||||
auto& bounds = bvh.flatBounds;
|
||||
auto& indices = bvh.indices;
|
||||
|
||||
outPairs.reserve(::reserveCount);
|
||||
if ( nodes.empty() ) return;
|
||||
outPairs.reserve( uf::physics::impl::settings.reserveCount );
|
||||
|
||||
for ( auto i = 0; i < nodes.size(); ++i ) {
|
||||
const auto& nodeA = nodes[i];
|
||||
for ( pod::BVH::index_t a = 0; a < nodes.size(); ++a ) {
|
||||
const auto& nodeA = nodes[a];
|
||||
if ( nodeA.getCount() <= 0 || nodeA.isAsleep() ) continue;
|
||||
|
||||
for ( auto j = i + 1; j < nodes.size(); ++j ) {
|
||||
const auto& nodeB = nodes[j];
|
||||
if ( nodeB.getCount() <= 0 || nodeB.isAsleep() ) continue;
|
||||
const auto& boundsA = bounds[a];
|
||||
pod::BVH::index_t b = a + 1;
|
||||
while ( b < nodes.size() ) {
|
||||
const auto& nodeB = nodes[b];
|
||||
|
||||
if ( !::aabbOverlap( bvh.flatBounds[i], bvh.flatBounds[j] ) ) continue;
|
||||
if ( nodeB.isAsleep() || !::aabbOverlap( boundsA, bounds[b] ) ) {
|
||||
b = nodeB.skipIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( auto ia = 0; ia < nodeA.getCount(); ++ia ) {
|
||||
for ( auto ib = 0; ib < nodeB.getCount(); ++ib ) {
|
||||
auto indexA = indices[nodeA.start + ia];
|
||||
auto indexB = indices[nodeB.start + ib];
|
||||
if ( nodeB.getCount() > 0 ) {
|
||||
for ( pod::BVH::index_t ia = 0; ia < nodeA.getCount(); ++ia ) {
|
||||
for ( pod::BVH::index_t ib = 0; ib < nodeB.getCount(); ++ib ) {
|
||||
auto indexA = indices[nodeA.start + ia];
|
||||
auto indexB = indices[nodeB.start + ib];
|
||||
|
||||
if ( indexA == indexB ) continue;
|
||||
if ( indexA > indexB ) std::swap( indexA, indexB );
|
||||
if ( indexA == indexB ) continue;
|
||||
if ( indexA > indexB ) std::swap(indexA, indexB);
|
||||
|
||||
outPairs.emplace( indexA, indexB );
|
||||
outPairs.emplace( indexA, indexB );
|
||||
}
|
||||
}
|
||||
}
|
||||
++b;
|
||||
}
|
||||
}
|
||||
}
|
||||
void queryFlatOverlaps( const pod::BVH& bvhA, const pod::BVH& bvhB, pod::BVH::pairs_t& outPairs ) {
|
||||
auto& nodesA = bvhA.flattened;
|
||||
auto& boundsA = bvhA.flatBounds;
|
||||
auto& indicesA = bvhA.indices;
|
||||
|
||||
|
||||
auto& nodesB = bvhB.flattened;
|
||||
auto& boundsB = bvhB.flatBounds;
|
||||
auto& indicesB = bvhB.indices;
|
||||
|
||||
if ( nodesA.empty() || nodesB.empty() ) return;
|
||||
|
||||
outPairs.reserve(::reserveCount);
|
||||
outPairs.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
for ( auto i = 0; i < nodesA.size(); ++i ) {
|
||||
const auto& nodeA = nodesA[i];
|
||||
for ( pod::BVH::index_t a = 0; a < nodesA.size(); ++a ) {
|
||||
const auto& nodeA = nodesA[a];
|
||||
if ( nodeA.getCount() <= 0 || nodeA.isAsleep() ) continue;
|
||||
|
||||
for ( auto j = 0; j < nodesB.size(); ++j ) {
|
||||
const auto& nodeB = nodesB[j];
|
||||
if ( nodeB.getCount() <= 0 || nodeB.isAsleep() ) continue;
|
||||
const auto& bA = boundsA[a];
|
||||
|
||||
if ( !::aabbOverlap( bvhA.flatBounds[i], bvhB.flatBounds[j] ) ) continue;
|
||||
pod::BVH::index_t b = 0;
|
||||
while ( b < nodesB.size() ) {
|
||||
const auto& nodeB = nodesB[b];
|
||||
|
||||
for ( auto ia = 0; ia < nodeA.getCount(); ++ia ) {
|
||||
for (auto ib = 0; ib < nodeB.getCount(); ++ib ) {
|
||||
auto indexA = indicesA[nodeA.start + ia];
|
||||
auto indexB = indicesB[nodeB.start + ib];
|
||||
if ( nodeB.isAsleep() || !::aabbOverlap(bA, boundsB[b]) ) {
|
||||
b = nodeB.skipIndex;
|
||||
continue;
|
||||
}
|
||||
|
||||
outPairs.emplace( indexA, indexB );
|
||||
if ( nodeB.getCount() > 0 ) {
|
||||
for ( pod::BVH::index_t ia = 0; ia < nodeA.getCount(); ++ia ) {
|
||||
for ( pod::BVH::index_t ib = 0; ib < nodeB.getCount(); ++ib ) {
|
||||
auto indexA = indicesA[nodeA.start + ia];
|
||||
auto indexB = indicesB[nodeB.start + ib];
|
||||
|
||||
outPairs.emplace(indexA, indexB);
|
||||
}
|
||||
}
|
||||
}
|
||||
++b;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -714,7 +735,7 @@ namespace {
|
||||
auto& nodes = bvh.flattened;
|
||||
auto& indices = bvh.indices;
|
||||
|
||||
outIndices.reserve(::reserveCount);
|
||||
outIndices.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
pod::BVH::index_t idx = 0;
|
||||
while ( idx < nodes.size() ) {
|
||||
@ -738,7 +759,7 @@ namespace {
|
||||
auto& nodes = bvh.flattened;
|
||||
auto& indices = bvh.indices;
|
||||
|
||||
outIndices.reserve(::reserveCount);
|
||||
outIndices.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
pod::BVH::index_t idx = 0;
|
||||
while ( idx < nodes.size() ) {
|
||||
@ -802,7 +823,8 @@ namespace {
|
||||
}
|
||||
|
||||
// map root to island index
|
||||
uf::stl::unordered_map<pod::BVH::index_t, pod::BVH::index_t> rootToIsland;
|
||||
static thread_local uf::stl::unordered_map<pod::BVH::index_t, pod::BVH::index_t> rootToIsland;
|
||||
rootToIsland.clear();
|
||||
|
||||
islands.clear();
|
||||
islands.reserve(bodies.size());
|
||||
|
||||
@ -61,9 +61,10 @@ namespace {
|
||||
uint64_t lhs = reinterpret_cast<uint64_t>(&a);
|
||||
uint64_t rhs = reinterpret_cast<uint64_t>(&b);
|
||||
if (lhs > rhs) std::swap(lhs, rhs);
|
||||
|
||||
lhs ^= rhs + 0x9e3779b97f4a7c15 + (lhs << 6) + (lhs >> 2);
|
||||
return lhs;
|
||||
size_t seed = 0;
|
||||
seed ^= std::hash<uint64_t>{}(lhs) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
seed ^= std::hash<uint64_t>{}(rhs) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
return seed;
|
||||
}
|
||||
|
||||
// marks a body as asleep
|
||||
@ -78,6 +79,7 @@ namespace {
|
||||
}
|
||||
void updateActivity( pod::PhysicsBody& body, float dt ) {
|
||||
// reset grounded state
|
||||
bool wasGrounded = body.activity.grounded;
|
||||
body.activity.grounded = false;
|
||||
|
||||
// already asleep
|
||||
@ -91,7 +93,7 @@ namespace {
|
||||
if ( linSpeed < pod::Activity::linearSleepEpsilon && angSpeed < pod::Activity::angularSleepEpsilon ) {
|
||||
body.activity.sleepTimer += dt;
|
||||
float threshold = pod::Activity::sleepThreshold;
|
||||
if ( body.activity.grounded ) threshold *= 0.25f;
|
||||
if ( wasGrounded ) threshold *= 0.25f;
|
||||
if ( body.activity.sleepTimer > threshold ) ::sleepBody( body );
|
||||
}
|
||||
// body is moving, reset timer
|
||||
@ -242,19 +244,24 @@ namespace {
|
||||
// check against AB
|
||||
float t = std::clamp(uf::vector::dot( ao, ab ) / d00, 0.0f, 1.0f);
|
||||
auto pAB = a + (ab * t);
|
||||
float distAB = uf::vector::dot( pAB, pAB );
|
||||
float distAB = uf::vector::dot( p - pAB, p - pAB );
|
||||
//float distAB = uf::vector::dot( pAB, pAB );
|
||||
|
||||
// check against AC
|
||||
float t2 = std::clamp(uf::vector::dot( ao, ac ) / d11, 0.0f, 1.0f);
|
||||
auto pAC = a + (ac * t2);
|
||||
float distAC = uf::vector::dot( pAC, pAC );
|
||||
float distAC = uf::vector::dot( p - pAC, p - pAC );
|
||||
//float distAC = uf::vector::dot( pAC, pAC );
|
||||
|
||||
// check against BC
|
||||
auto bc = c - b;
|
||||
float d22 = uf::vector::dot( bc, bc );
|
||||
float t3 = std::clamp(uf::vector::dot( -b, bc ) / d22, 0.0f, 1.0f);
|
||||
float t3 = std::clamp(uf::vector::dot( p - b, bc ) / d22, 0.0f, 1.0f);
|
||||
//float t3 = std::clamp(uf::vector::dot( -b, bc ) / d22, 0.0f, 1.0f);
|
||||
|
||||
auto pBC = b + ( bc * t3 );
|
||||
float distBC = uf::vector::dot( pBC, pBC );
|
||||
float distBC = uf::vector::dot( p - pBC, p - pBC );
|
||||
//float distBC = uf::vector::dot( pBC, pBC );
|
||||
|
||||
// pick closest edge/vertex
|
||||
if ( distAB <= distAC && distAB <= distBC ) return { 1.0f - t, t, 0.0f };
|
||||
|
||||
@ -4,50 +4,6 @@
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
#include <uf/utils/memory/stack.h>
|
||||
|
||||
namespace {
|
||||
bool warmupSolver = true; // cache manifold data to warm up the solver
|
||||
bool blockContactSolver = true; // use BlockNxN solvers (where N = number of contacts for a manifold)
|
||||
bool psgContactSolver = true; // use PSG contact solver
|
||||
bool useGjk = false; // currently don't have a way to broadphase mesh => narrowphase tri via GJK
|
||||
bool fixedStep = false; // run physics simulation with a fixed delta time (with accumulation), rather than rely on actual engine deltatime
|
||||
uint32_t substeps = 4; // number of substeps per frame tick
|
||||
uint32_t reserveCount = 32; // amount of elements to reserve for vectors used in this system, to-do: have it tie to a memory pool allocator
|
||||
|
||||
// increasing these make things lag for reasons I can imagine why
|
||||
uint32_t broadphaseBvhCapacity = 4; // number of bodies per leaf node
|
||||
uint32_t meshBvhCapacity = 4; // number of triangles per leaf node
|
||||
|
||||
// additionally flattens a BVH for linear iteration, rather than a recursive / stack-based traversal
|
||||
bool flattenBvhBodies = true;
|
||||
bool flattenBvhMeshes = true;
|
||||
|
||||
// use surface area heuristics for building the BVH, rather than naive splits
|
||||
bool useBvhSahBodies = true; // it actually seems slower to use these......
|
||||
bool useBvhSahMeshes = true;
|
||||
|
||||
bool useSplitBvhs = true; // creates separate BVHs for static / dynamic objects
|
||||
|
||||
// to-do: find possibly better values for this
|
||||
uint32_t solverIterations = 10;
|
||||
float baumgarteCorrectionPercent = 0.4f;
|
||||
float baumgarteCorrectionSlop = 0.01f;
|
||||
|
||||
uf::stl::unordered_map<size_t, pod::Manifold> manifoldsCache;
|
||||
uint32_t manifoldCacheLifetime = 6; // to-do: find a good value for this
|
||||
|
||||
uint32_t frameCounter = 0;
|
||||
|
||||
// to-do: tweak this to not be annoying
|
||||
pod::BVH::UpdatePolicy bvhUpdatePolicy = {
|
||||
.displacementThreshold = 0.25f,
|
||||
.overlapThreshold = 2.0f,
|
||||
.dirtyRatioThreshold = 0.3f,
|
||||
.maxFramesBeforeRebuild = 60, // * 10, // 10 seconds
|
||||
};
|
||||
|
||||
float groundedThreshold = 0.7f; // threshold before marking a body as grounded
|
||||
}
|
||||
|
||||
#define EPS(x) 1.0e-6f
|
||||
#define EPS2 (EPS(1.0e-6) * EPS(1.0e-6))
|
||||
#define ASSERT_COLLIDER_TYPES( A, B ) UF_ASSERT( a.collider.type == pod::ShapeType::A && b.collider.type == pod::ShapeType::B );
|
||||
@ -67,8 +23,12 @@ namespace {
|
||||
#include "integration.inl"
|
||||
#include "solvers.inl"
|
||||
|
||||
// unused, as these are from reactphysics
|
||||
pod::PhysicsSettings uf::physics::impl::settings;
|
||||
|
||||
float uf::physics::impl::timescale = 1.0f / 60.0f;
|
||||
bool uf::physics::impl::async = false;
|
||||
|
||||
// unused, as these are from reactphysics
|
||||
bool uf::physics::impl::interpolate = false;
|
||||
bool uf::physics::impl::shared = false;
|
||||
bool uf::physics::impl::globalStorage = false;
|
||||
@ -90,9 +50,8 @@ void uf::physics::impl::tick( uf::Object& object, float dt ) {
|
||||
uf::physics::impl::tick( object.getComponent<pod::World>(), dt );
|
||||
}
|
||||
void uf::physics::impl::tick( pod::World& world, float dt ) {
|
||||
if ( !::fixedStep ) {
|
||||
|
||||
if ( ::substeps > 0 ) uf::physics::impl::substep( world, dt, ::substeps );
|
||||
if ( !uf::physics::impl::settings.fixedStep ) {
|
||||
if ( uf::physics::impl::settings.substeps > 0 ) uf::physics::impl::substep( world, dt, uf::physics::impl::settings.substeps );
|
||||
else uf::physics::impl::step( world, dt );
|
||||
|
||||
return;
|
||||
@ -101,7 +60,7 @@ void uf::physics::impl::tick( pod::World& world, float dt ) {
|
||||
static float accumulator = 0;
|
||||
accumulator += dt;
|
||||
while ( accumulator >= uf::physics::impl::timescale ) {
|
||||
if ( ::substeps > 0 ) uf::physics::impl::substep( world, uf::physics::impl::timescale, ::substeps );
|
||||
if ( uf::physics::impl::settings.substeps > 0 ) uf::physics::impl::substep( world, uf::physics::impl::timescale, uf::physics::impl::settings.substeps );
|
||||
else uf::physics::impl::step( world, uf::physics::impl::timescale );
|
||||
accumulator -= uf::physics::impl::timescale;
|
||||
}
|
||||
@ -130,20 +89,20 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
|
||||
if ( bodies.empty() ) return;
|
||||
|
||||
++::frameCounter;
|
||||
++uf::physics::impl::settings.frameCounter;
|
||||
|
||||
for ( auto* body : bodies ) {
|
||||
::integrate( *body, dt );
|
||||
}
|
||||
|
||||
// rebuild static bvh if dirty
|
||||
if ( staticBvh.dirty && ::useSplitBvhs ) {
|
||||
::buildBroadphaseBVH( staticBvh, bodies, ::broadphaseBvhCapacity, ::useSplitBvhs, true ); // (re)build
|
||||
if ( staticBvh.dirty && uf::physics::impl::settings.useSplitBvhs ) {
|
||||
::buildBroadphaseBVH( staticBvh, bodies, uf::physics::impl::settings.broadphaseBvhCapacity, uf::physics::impl::settings.useSplitBvhs, true ); // (re)build
|
||||
}
|
||||
|
||||
switch ( ::decideBVHUpdate( dynamicBvh, bodies, ::bvhUpdatePolicy, ::frameCounter ) ) {
|
||||
switch ( ::decideBVHUpdate( dynamicBvh, bodies, uf::physics::impl::settings.bvhUpdatePolicy, uf::physics::impl::settings.frameCounter ) ) {
|
||||
case pod::BVH::UpdatePolicy::Decision::REBUILD: {
|
||||
::buildBroadphaseBVH( dynamicBvh, bodies, ::broadphaseBvhCapacity, ::useSplitBvhs, false ); // (re)build
|
||||
::buildBroadphaseBVH( dynamicBvh, bodies, uf::physics::impl::settings.broadphaseBvhCapacity, uf::physics::impl::settings.useSplitBvhs, false ); // (re)build
|
||||
} break;
|
||||
case pod::BVH::UpdatePolicy::Decision::REFIT: {
|
||||
::refitBVH( dynamicBvh, bodies ); // refit
|
||||
@ -157,7 +116,7 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
// query for overlaps
|
||||
pod::BVH::pairs_t pairs;
|
||||
::queryOverlaps( dynamicBvh, pairs );
|
||||
if ( ::useSplitBvhs ) {
|
||||
if ( uf::physics::impl::settings.useSplitBvhs ) {
|
||||
::queryOverlaps( dynamicBvh, staticBvh, pairs );
|
||||
}
|
||||
|
||||
@ -165,13 +124,14 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
uf::stl::vector<pod::Island> islands;
|
||||
::buildIslands( pairs, bodies, islands );
|
||||
|
||||
if ( ::warmupSolver ) ::prepareManifoldCache( ::manifoldsCache, islands, bodies );
|
||||
if ( uf::physics::impl::settings.warmupSolver ) ::prepareManifoldCache( uf::physics::impl::settings.manifoldsCache, islands, bodies );
|
||||
|
||||
// iterate islands
|
||||
#pragma omp parallel for schedule(dynamic)
|
||||
for ( auto& island : islands ) {
|
||||
uf::stl::vector<pod::Manifold> manifolds;
|
||||
manifolds.reserve(::reserveCount);
|
||||
static thread_local uf::stl::vector<pod::Manifold> manifolds;
|
||||
manifolds.clear();
|
||||
manifolds.reserve(uf::physics::impl::settings.reserveCount);
|
||||
|
||||
// sleeping island, skip
|
||||
if ( !::updateIsland( island, bodies, dt ) ) continue;
|
||||
@ -190,9 +150,9 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
for ( auto& c : manifold.points ) c.normal = ::orientNormalToAB( a, b, c.normal );
|
||||
}
|
||||
// retrieve accumulated impulses
|
||||
if ( ::warmupSolver ) {
|
||||
auto it = ::manifoldsCache.find( ::makePairKey( a, b ) );
|
||||
if ( it != ::manifoldsCache.end() ) ::retrieveContacts( manifold, it->second );
|
||||
if ( uf::physics::impl::settings.warmupSolver ) {
|
||||
auto it = uf::physics::impl::settings.manifoldsCache.find( ::makePairKey( a, b ) );
|
||||
if ( it != uf::physics::impl::settings.manifoldsCache.end() ) ::retrieveContacts( manifold, it->second );
|
||||
}
|
||||
// merge similar contacts from a mesh to ensure continuity
|
||||
if ( a.collider.type == pod::ShapeType::MESH || b.collider.type == pod::ShapeType::MESH ) {
|
||||
@ -207,7 +167,7 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
if ( b.activity.awake && !a.activity.awake ) ::wakeBody( a );
|
||||
// mark as grounded
|
||||
for ( auto& c : manifold.points ) {
|
||||
if ( std::fabs(uf::vector::dot(c.normal, pod::Vector3f{0,1,0})) > ::groundedThreshold ) {
|
||||
if ( std::fabs(uf::vector::dot(c.normal, pod::Vector3f{0,1,0})) > uf::physics::impl::settings.groundedThreshold ) {
|
||||
// only mark if contact point is below body
|
||||
if ( c.point.y < getPosition(a).y ) a.activity.grounded = true;
|
||||
if ( c.point.y < getPosition(b).y ) b.activity.grounded = true;
|
||||
@ -223,12 +183,12 @@ void uf::physics::impl::step( pod::World& world, float dt ) {
|
||||
// do position correction
|
||||
::solvePositions( manifolds, dt );
|
||||
// cache manifold positions
|
||||
if ( ::warmupSolver ) {
|
||||
::updateManifoldCache( manifolds, ::manifoldsCache );
|
||||
if ( uf::physics::impl::settings.warmupSolver ) {
|
||||
::updateManifoldCache( manifolds, uf::physics::impl::settings.manifoldsCache );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ::warmupSolver ) ::pruneManifoldCache( ::manifoldsCache );
|
||||
if ( uf::physics::impl::settings.warmupSolver ) ::pruneManifoldCache( uf::physics::impl::settings.manifoldsCache );
|
||||
|
||||
for ( auto* b : bodies ) {
|
||||
if ( b->isStatic ) continue;
|
||||
@ -381,7 +341,7 @@ void uf::physics::impl::applyForce( pod::PhysicsBody& body, const pod::Vector3f&
|
||||
if ( body.isStatic ) return; ::wakeBody( body );
|
||||
body.forceAccumulator += force;
|
||||
}
|
||||
void uf::physics::impl::applyForceAtPoint( pod::PhysicsBody body, const pod::Vector3f& force, const pod::Vector3f& point ) {
|
||||
void uf::physics::impl::applyForceAtPoint( pod::PhysicsBody& body, const pod::Vector3f& force, const pod::Vector3f& point ) {
|
||||
if ( body.isStatic ) return; ::wakeBody( body );
|
||||
// linear force
|
||||
body.forceAccumulator += force;
|
||||
@ -483,7 +443,7 @@ pod::PhysicsBody& uf::physics::impl::create( pod::World& world, uf::Object& obje
|
||||
|
||||
body.collider.mesh.bvh = new pod::BVH;
|
||||
auto& bvh = *body.collider.mesh.bvh;
|
||||
::buildMeshBVH( bvh, mesh, ::meshBvhCapacity );
|
||||
::buildMeshBVH( bvh, mesh, uf::physics::impl::settings.meshBvhCapacity );
|
||||
|
||||
body.bounds = ::computeAABB( body );
|
||||
uf::physics::impl::updateInertia( body );
|
||||
@ -562,7 +522,7 @@ pod::RayQuery uf::physics::impl::rayCast( const pod::Ray& ray, const pod::World&
|
||||
static thread_local uf::stl::vector<pod::BVH::index_t> candidates;
|
||||
candidates.clear();
|
||||
::queryBVH( dynamicBvh, ray, candidates );
|
||||
if ( ::useSplitBvhs ) ::queryBVH( staticBvh, ray, candidates );
|
||||
if ( uf::physics::impl::settings.useSplitBvhs ) ::queryBVH( staticBvh, ray, candidates );
|
||||
|
||||
for ( auto i : candidates ) {
|
||||
auto* b = bodies[i];
|
||||
|
||||
@ -24,11 +24,15 @@ namespace {
|
||||
void applyImpulseTo( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& impulse ) {
|
||||
if ( !a.isStatic ) {
|
||||
a.velocity -= impulse * a.inverseMass;
|
||||
a.angularVelocity -= (uf::vector::cross(rA, impulse)) * a.inverseInertiaTensor;
|
||||
//a.angularVelocity -= (uf::vector::cross(rA, impulse)) * a.inverseInertiaTensor;
|
||||
pod::Matrix3f invIa = computeWorldInverseInertia( a );
|
||||
a.angularVelocity -= uf::matrix::multiply( invIa, uf::vector::cross(rA, impulse) );
|
||||
}
|
||||
if ( !b.isStatic ) {
|
||||
b.velocity += impulse * b.inverseMass;
|
||||
b.angularVelocity += (uf::vector::cross(rB, impulse)) * b.inverseInertiaTensor;
|
||||
//b.angularVelocity += (uf::vector::cross(rB, impulse)) * b.inverseInertiaTensor;
|
||||
pod::Matrix3f invIb = computeWorldInverseInertia( b );
|
||||
a.angularVelocity += uf::matrix::multiply( invIb, uf::vector::cross(rB, impulse) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +69,7 @@ namespace {
|
||||
}
|
||||
|
||||
bool generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
||||
if ( ::useGjk ) return generateContactsGjk( a, b, manifold, dt );
|
||||
if ( uf::physics::impl::settings.useGjk ) return generateContactsGjk( a, b, manifold, dt );
|
||||
::bindManifold( a, b, manifold, dt );
|
||||
|
||||
#define CHECK_CONTACT( A, B, fun )\
|
||||
@ -111,7 +115,8 @@ namespace {
|
||||
void reduceContacts( pod::Manifold& manifold ) {
|
||||
if ( manifold.points.size() <= 4 ) return;
|
||||
|
||||
uf::stl::vector<pod::Contact> result;
|
||||
static thread_local uf::stl::vector<pod::Contact> result;
|
||||
result.clear();
|
||||
result.reserve(4);
|
||||
|
||||
for ( auto& c : manifold.points ) {
|
||||
@ -200,7 +205,7 @@ namespace {
|
||||
|
||||
// prune points that are too old
|
||||
for ( auto it = manifold.points.begin(); it != manifold.points.end(); ) {
|
||||
if ( it->lifetime > ::manifoldCacheLifetime ) it = manifold.points.erase(it);
|
||||
if ( it->lifetime > uf::physics::impl::settings.manifoldCacheLifetime ) it = manifold.points.erase(it);
|
||||
else ++it;
|
||||
}
|
||||
|
||||
@ -251,11 +256,11 @@ namespace {
|
||||
|
||||
// baumgarte position correction
|
||||
void positionCorrection( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& contact ) {
|
||||
if ( ::baumgarteCorrectionPercent <= 0 ) return;
|
||||
if ( uf::physics::impl::settings.baumgarteCorrectionPercent <= 0 ) return;
|
||||
if ( a.isStatic && b.isStatic ) return;
|
||||
|
||||
// penetration depth beyond slop
|
||||
float penetration = std::max( contact.penetration - ::baumgarteCorrectionSlop, 0.0f );
|
||||
float penetration = std::max( contact.penetration - uf::physics::impl::settings.baumgarteCorrectionSlop, 0.0f );
|
||||
if ( penetration <= 0.0f ) return;
|
||||
|
||||
// compute correction magnitude
|
||||
@ -265,7 +270,7 @@ namespace {
|
||||
if ( totalInvMass <= EPS(1e-8f) ) return;
|
||||
|
||||
// apply correction vector
|
||||
pod::Vector3f correction = contact.normal * (penetration / totalInvMass) * ::baumgarteCorrectionPercent;
|
||||
pod::Vector3f correction = contact.normal * (penetration / totalInvMass) * uf::physics::impl::settings.baumgarteCorrectionPercent;
|
||||
|
||||
if ( !a.isStatic ) a.transform->position -= correction * invMassA;
|
||||
if ( !b.isStatic ) b.transform->position += correction * invMassB;
|
||||
|
||||
@ -37,7 +37,7 @@ namespace {
|
||||
if ( dist > r ) return false;
|
||||
|
||||
float penetration = r - dist;
|
||||
auto contact = center - normal * dist - normal * penetration;
|
||||
auto contact = center - normal * r;
|
||||
|
||||
manifold.points.emplace_back(pod::Contact{ contact, normal, penetration });
|
||||
return true;
|
||||
|
||||
@ -26,7 +26,7 @@ namespace {
|
||||
// normal impulse scalar
|
||||
float jn = -(1.0f + e) * velAlongNormal;
|
||||
jn /= invMassN;
|
||||
if ( ::warmupSolver ) {
|
||||
if ( uf::physics::impl::settings.warmupSolver ) {
|
||||
float jnOld = contact.accumulatedNormalImpulse;
|
||||
float jnNew = std::max(0.0f, jnOld + jn);
|
||||
float jnDelta = jnNew - jnOld;
|
||||
@ -57,7 +57,7 @@ namespace {
|
||||
|
||||
if ( std::fabs(jt) > jn * mu_s) jt = -jn * mu_d; // dynamic friction: resist sliding proportionally
|
||||
|
||||
if ( ::warmupSolver ) {
|
||||
if ( uf::physics::impl::settings.warmupSolver ) {
|
||||
float maxFriction = mu_s * contact.accumulatedNormalImpulse;
|
||||
float jtOld = contact.accumulatedTangentImpulse;
|
||||
float jtNew = std::max(-maxFriction, std::min(jtOld + jt, maxFriction));
|
||||
@ -83,6 +83,9 @@ namespace {
|
||||
// precompute inverse masses
|
||||
float invMassA = ( a.isStatic ? 0.0f : a.inverseMass );
|
||||
float invMassB = ( b.isStatic ? 0.0f : b.inverseMass );
|
||||
|
||||
pod::Matrix3f invIa = computeWorldInverseInertia( a );
|
||||
pod::Matrix3f invIb = computeWorldInverseInertia( b );
|
||||
|
||||
auto pA = ::getPosition( a, true );
|
||||
auto pB = ::getPosition( b, true );
|
||||
@ -90,12 +93,11 @@ namespace {
|
||||
for ( auto i = 0; i < N; i++ ) {
|
||||
pod::Vector3f rA_i = manifold.points[i].point - pA;
|
||||
pod::Vector3f rB_i = manifold.points[i].point - pB;
|
||||
|
||||
pod::Vector3f n_i = manifold.points[i].normal;
|
||||
|
||||
for ( auto j = 0; j < N; j++ ) {
|
||||
pod::Vector3f rA_j = manifold.points[j].point - pA;
|
||||
pod::Vector3f rB_j = manifold.points[j].point - pB;
|
||||
|
||||
pod::Vector3f n_i = manifold.points[i].normal;
|
||||
pod::Vector3f n_j = manifold.points[j].normal;
|
||||
|
||||
float termLinear = (invMassA + invMassB) * uf::vector::dot(n_i, n_j);
|
||||
@ -104,8 +106,6 @@ namespace {
|
||||
pod::Vector3f raXnj = uf::vector::cross(rA_j, n_j);
|
||||
pod::Vector3f rbXnj = uf::vector::cross(rB_j, n_j);
|
||||
|
||||
pod::Matrix3f invIa = computeWorldInverseInertia( a );
|
||||
pod::Matrix3f invIb = computeWorldInverseInertia( b );
|
||||
|
||||
pod::Vector3f Ia_raXnj = uf::matrix::multiply( invIa, raXnj );
|
||||
pod::Vector3f Ib_rbXnj = uf::matrix::multiply( invIb, rbXnj );
|
||||
@ -126,7 +126,7 @@ namespace {
|
||||
for ( auto i = 0; i < N; i++ ) {
|
||||
float vRel = uf::vector::dot( relVelLinear, manifold.points[i].normal );
|
||||
|
||||
float penetrationBias = std::max( manifold.points[i].penetration - ::baumgarteCorrectionSlop, 0.0f ) * ( ::baumgarteCorrectionPercent / dt );
|
||||
float penetrationBias = std::max( manifold.points[i].penetration - uf::physics::impl::settings.baumgarteCorrectionSlop, 0.0f ) * ( uf::physics::impl::settings.baumgarteCorrectionPercent / dt );
|
||||
float cDot = vRel + penetrationBias;
|
||||
|
||||
rhs[i] = (cDot < 0.0f) ? -cDot : 0.0f;
|
||||
@ -141,7 +141,7 @@ namespace {
|
||||
float vRel = uf::vector::dot((vB - vA), contact.normal);
|
||||
|
||||
// penetration bias with clamp
|
||||
float penetrationBias = std::max(contact.penetration - ::baumgarteCorrectionSlop, 0.0f) * (::baumgarteCorrectionPercent / dt);
|
||||
float penetrationBias = std::max(contact.penetration - uf::physics::impl::settings.baumgarteCorrectionSlop, 0.0f) * (uf::physics::impl::settings.baumgarteCorrectionPercent / dt);
|
||||
penetrationBias = std::min(penetrationBias, 2.0f / dt); // clamp
|
||||
|
||||
float maxPenetrationRecovery = 2.0f; // limit to 2 units per second
|
||||
@ -214,7 +214,7 @@ namespace {
|
||||
|
||||
// restitution bias + baumgarte
|
||||
float e = std::min( a.material.restitution, b.material.restitution );
|
||||
float penetrationBias = std::max( c.penetration - ::baumgarteCorrectionSlop, 0.0f ) * (::baumgarteCorrectionPercent / dt);
|
||||
float penetrationBias = std::max( c.penetration - uf::physics::impl::settings.baumgarteCorrectionSlop, 0.0f ) * (uf::physics::impl::settings.baumgarteCorrectionPercent / dt);
|
||||
cc.bias = (vn < -1.0f ? -e * vn : 0.0f) + penetrationBias;
|
||||
|
||||
// effective mass (normal)
|
||||
@ -232,6 +232,7 @@ namespace {
|
||||
cc.effectiveMassT = ( Kt > 0.0f ) ? ( 1.0f / Kt ) : 0.0f;
|
||||
|
||||
// warm start
|
||||
#if 1
|
||||
cc.accumulatedNormalImpulse = c.accumulatedNormalImpulse;
|
||||
cc.accumulatedTangentImpulse = c.accumulatedTangentImpulse;
|
||||
|
||||
@ -239,10 +240,11 @@ namespace {
|
||||
pod::Vector3f P = cc.normal * cc.accumulatedNormalImpulse + cc.tangent * cc.accumulatedTangentImpulse;
|
||||
|
||||
::applyImpulseTo(a, b, cc.rA, cc.rB, P);
|
||||
#endif
|
||||
}
|
||||
|
||||
// iterative PGS
|
||||
for ( auto iter = 0; iter < ::solverIterations; iter++ ) {
|
||||
for ( auto iter = 0; iter < uf::physics::impl::settings.solverIterations; iter++ ) {
|
||||
for ( auto i = 0; i < count; i++ ) {
|
||||
auto& cc = cache[i];
|
||||
|
||||
@ -280,18 +282,18 @@ namespace {
|
||||
}
|
||||
|
||||
void resolveManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
||||
if ( ::blockContactSolver ) {
|
||||
if ( uf::physics::impl::settings.blockContactSolver ) {
|
||||
if ( manifold.points.size() == 2 ) return ::block2x2Solver( a, b, manifold, dt );
|
||||
if ( manifold.points.size() == 3 ) return ::block3x3Solver( a, b, manifold, dt );
|
||||
if ( manifold.points.size() == 4 ) return ::block4x4Solver( a, b, manifold, dt );
|
||||
}
|
||||
if ( ::psgContactSolver ) return ::blockPGSSolver( a, b, manifold, dt );
|
||||
if ( uf::physics::impl::settings.psgContactSolver ) return ::blockPGSSolver( a, b, manifold, dt );
|
||||
for ( auto& contact : manifold.points ) ::iterativeImpulseSolver( a, b, contact, dt );
|
||||
}
|
||||
|
||||
void solveContacts( uf::stl::vector<pod::Manifold>& manifolds, float dt ) {
|
||||
if ( ::warmupSolver ) for ( auto& manifold : manifolds ) ::warmupManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||
for ( auto i = 0; i < ::solverIterations; ++i ) for ( auto& manifold : manifolds ) ::resolveManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||
if ( uf::physics::impl::settings.warmupSolver ) for ( auto& manifold : manifolds ) ::warmupManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||
for ( auto i = 0; i < uf::physics::impl::settings.solverIterations; ++i ) for ( auto& manifold : manifolds ) ::resolveManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||
}
|
||||
|
||||
void solvePositions( uf::stl::vector<pod::Manifold>& manifolds, float dt, uint32_t iterations = 2 ) {
|
||||
|
||||
@ -37,11 +37,6 @@ void uf::thread::tick( pod::Thread& thread ) {
|
||||
thread.timer.start();
|
||||
|
||||
while ( thread.running ) {
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
thread.conditions.queued.wait(lock, [&]{
|
||||
return (!thread.container.empty() || !thread.queue.empty()) || !thread.running;
|
||||
});
|
||||
|
||||
uf::thread::process( thread );
|
||||
|
||||
if ( thread.limiter > 0 ) {
|
||||
@ -57,7 +52,7 @@ void uf::thread::tick( pod::Thread& thread ) {
|
||||
|
||||
pod::Thread& uf::thread::fetchWorker( const uf::stl::string& name ) {
|
||||
static int current = 0;
|
||||
static int limit = uf::thread::workers;
|
||||
int limit = uf::thread::workers;
|
||||
int tries = 0;
|
||||
|
||||
while ( tries++ < limit ) {
|
||||
@ -153,12 +148,25 @@ void uf::thread::queue( pod::Thread& thread, const pod::Thread::function_t& func
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
thread.queue.emplace( function );
|
||||
thread.conditions.queued.notify_one();
|
||||
thread.pending.fetch_add(1);
|
||||
if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
}
|
||||
void uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) )return; //ops
|
||||
while ( !thread.queue.empty() ) {
|
||||
auto& function = thread.queue.front();
|
||||
if ( function )
|
||||
void uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) return; // ops
|
||||
pod::Thread::queue_t local_queue;
|
||||
pod::Thread::container_t local_container;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
thread.conditions.queued.wait(lock, [&]{
|
||||
return (!thread.container.empty() || !thread.queue.empty()) || !thread.running;
|
||||
});
|
||||
|
||||
if ( !thread.running ) return;
|
||||
std::swap( local_queue, thread.queue );
|
||||
}
|
||||
|
||||
while ( !local_queue.empty() ) {
|
||||
auto& function = local_queue.front();
|
||||
#if UF_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
@ -168,10 +176,17 @@ void uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thre
|
||||
UF_MSG_ERROR("Thread {} (UID: {}) caught exception: {}", thread.name, thread.uid, e.what());
|
||||
}
|
||||
#endif
|
||||
thread.queue.pop();
|
||||
|
||||
local_queue.pop();
|
||||
thread.pending.fetch_sub(1);
|
||||
}
|
||||
for ( auto function : thread.container ) {
|
||||
if ( function )
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
local_container = thread.container;
|
||||
}
|
||||
|
||||
for ( auto& function : local_container ) {
|
||||
#if UF_EXCEPTIONS
|
||||
try {
|
||||
#endif
|
||||
@ -182,7 +197,11 @@ void uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thre
|
||||
}
|
||||
#endif
|
||||
}
|
||||
thread.conditions.finished.notify_one();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*thread.mutex);
|
||||
thread.conditions.finished.notify_all();
|
||||
}
|
||||
}
|
||||
void uf::thread::wait( pod::Thread& thread ) {
|
||||
if ( thread.mutex != NULL ) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user