Commit for 2022.06.18 23-45-31.7z
This commit is contained in:
parent
4b7a9d5714
commit
70162646cb
4
Makefile
4
Makefile
@ -59,7 +59,7 @@ ifneq (,$(findstring win64,$(ARCH)))
|
||||
REQ_DEPS += $(RENDERER) json:nlohmann png zlib openal ogg freetype curl luajit reactphysics meshoptimizer xatlas simd ctti gltf # ncurses openvr draco discord bullet ultralight-ux
|
||||
FLAGS +=
|
||||
DEPS += -lgdi32
|
||||
LINKS += -Wl,-subsystem,windows
|
||||
LINKS += #-Wl,-subsystem,windows
|
||||
else ifneq (,$(findstring dreamcast,$(ARCH)))
|
||||
REQ_DEPS += simd opengl gldc json:nlohmann reactphysics png zlib ctti # lua ogg openal aldc gltf freetype bullet meshoptimizer draco luajit ultralight-ux ncurses curl openvr discord
|
||||
endif
|
||||
@ -304,7 +304,7 @@ $(TARGET): $(OBJS)
|
||||
endif
|
||||
|
||||
%.spv: %.glsl
|
||||
$(GLSLC) -std=450 -o $@ $<
|
||||
$(GLSLC) --target-env=vulkan1.2 -o $@ $<
|
||||
$(SPV_OPTIMIZER) --preserve-bindings --preserve-spec-constants -O $@ -o $@
|
||||
|
||||
clean:
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
{
|
||||
"engine": {
|
||||
"scenes": {
|
||||
"start": "McDonalds",
|
||||
"start": "SS2",
|
||||
"meshes": { "interleaved": false },
|
||||
"matrix": { "reverseInfinite": true },
|
||||
"lights": { "enabled": true,
|
||||
"useLightmaps": true,
|
||||
"max": 16
|
||||
"max": 32
|
||||
},
|
||||
"shadows": {
|
||||
"enabled": true,
|
||||
"update": 2,
|
||||
"max": 8,
|
||||
"max": 16,
|
||||
"samples": 1
|
||||
},
|
||||
"textures": {
|
||||
@ -48,7 +48,7 @@
|
||||
"ext": {
|
||||
"vulkan": {
|
||||
"validation": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"filters": [
|
||||
"MessageID = 0x4dae5635", // UNASSIGNED-CoreValidation-DrawState-InvalidImageLayout (false positive for cubemaps)
|
||||
"MessageID = 0x609a13b", // UNASSIGNED-CoreValidation-Shader-OutputNotConsumed (from depth-only calls)
|
||||
@ -74,7 +74,7 @@
|
||||
// "size": [ 960, 540 ]
|
||||
// "size": [ 640, 480 ]
|
||||
},
|
||||
"gpu": "auto",
|
||||
"gpu": 1,
|
||||
"experimental": {
|
||||
"batch queue submissions": false,
|
||||
"dedicated thread": false
|
||||
@ -120,7 +120,14 @@
|
||||
],
|
||||
"device": [
|
||||
"VK_KHR_swapchain",
|
||||
"VK_EXT_shader_viewport_index_layer"
|
||||
"VK_EXT_shader_viewport_index_layer",
|
||||
"VK_KHR_acceleration_structure",
|
||||
"VK_KHR_ray_tracing_pipeline",
|
||||
"VK_KHR_buffer_device_address",
|
||||
"VK_KHR_deferred_host_operations",
|
||||
"VK_EXT_descriptor_indexing",
|
||||
"VK_KHR_spirv_1_4",
|
||||
"VK_KHR_shader_float_controls"
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -198,7 +205,7 @@
|
||||
"streams by default": true
|
||||
},
|
||||
"memory pool": {
|
||||
"enabled": false,
|
||||
"enabled": true,
|
||||
"subPools": true,
|
||||
"alignment": 64,
|
||||
"override": false,
|
||||
@ -209,14 +216,14 @@
|
||||
"component": "128 MiB"
|
||||
}
|
||||
},
|
||||
"render modes": { "gui": true, "deferred": true },
|
||||
"render modes": { "gui": true, "deferred": true, "raytrace": true },
|
||||
"limiters": {
|
||||
"deltaTime": 5,
|
||||
"framerate": "auto"
|
||||
},
|
||||
"threads": {
|
||||
"workers" : "auto",
|
||||
"frame limiter": "auto"
|
||||
"frame limiter": 0 // "auto"
|
||||
},
|
||||
"debug": {
|
||||
"framerate": {
|
||||
|
||||
47
bin/data/shaders/raytrace/shader.gen.glsl
Normal file
47
bin/data/shaders/raytrace/shader.gen.glsl
Normal file
@ -0,0 +1,47 @@
|
||||
#version 460
|
||||
#extension GL_EXT_ray_tracing : enable
|
||||
#pragma shader_stage(raygen)
|
||||
layout (constant_id = 0) const uint PASSES = 2;
|
||||
|
||||
#include "../common/macros.h"
|
||||
#include "../common/structs.h"
|
||||
|
||||
layout (binding = 0) uniform UBO {
|
||||
EyeMatrices eyes[2];
|
||||
} ubo;
|
||||
layout (binding = 1) uniform accelerationStructureEXT inTlas;
|
||||
layout (binding = 2, rgba8) uniform volatile coherent image2D outImage;
|
||||
|
||||
layout (location = 0) rayPayloadEXT vec4 hitValue;
|
||||
|
||||
layout( push_constant ) uniform PushBlock {
|
||||
uint pass;
|
||||
uint draw;
|
||||
} PushConstant;
|
||||
|
||||
void main() {
|
||||
{
|
||||
surface.pass = PushConstant.pass;
|
||||
|
||||
const vec2 inUv = (vec2(gl_LaunchIDEXT.xy) + vec2(0.5)) / vec2(gl_LaunchSizeEXT.xy);
|
||||
|
||||
const mat4 iProjectionView = inverse( ubo.eyes[surface.pass].projection * mat4(mat3(ubo.eyes[surface.pass].view)) );
|
||||
const vec4 near4 = iProjectionView * (vec4(2.0 * inUv - 1.0, -1.0, 1.0));
|
||||
const vec4 far4 = iProjectionView * (vec4(2.0 * inUv - 1.0, 1.0, 1.0));
|
||||
const vec3 near3 = near4.xyz / near4.w;
|
||||
const vec3 far3 = far4.xyz / far4.w;
|
||||
|
||||
surface.ray.direction = normalize( far3 - near3 );
|
||||
surface.ray.origin = ubo.eyes[surface.pass].eyePos.xyz;
|
||||
}
|
||||
|
||||
uint rayFlags = gl_RayFlagsOpaqueEXT;
|
||||
uint cullMask = 0xFF;
|
||||
float tMin = 0.001;
|
||||
float tMax = 10000.0;
|
||||
|
||||
hitValue = vec4(1, 0, 1, 1);
|
||||
traceRayEXT(inTlas, rayFlags, cullMask, 0, 0, 0, surface.ray.origin.xyz, tMin, surface.ray.direction.xyz, tMax, 0);
|
||||
|
||||
imageStore(outImage, ivec2(gl_LaunchIDEXT.xy), vec4(hitValue));
|
||||
}
|
||||
12
bin/data/shaders/raytrace/shader.hit.glsl
Normal file
12
bin/data/shaders/raytrace/shader.hit.glsl
Normal file
@ -0,0 +1,12 @@
|
||||
#version 460
|
||||
#extension GL_EXT_ray_tracing : enable
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
#pragma shader_stage(closest)
|
||||
|
||||
layout(location = 0) rayPayloadInEXT vec4 hitValue;
|
||||
hitAttributeEXT vec2 attribs;
|
||||
|
||||
void main() {
|
||||
const vec3 barycentricCoords = vec3(1.0f - attribs.x - attribs.y, attribs.x, attribs.y);
|
||||
hitValue = vec4(barycentricCoords, 1.0);
|
||||
}
|
||||
9
bin/data/shaders/raytrace/shader.miss.glsl
Normal file
9
bin/data/shaders/raytrace/shader.miss.glsl
Normal file
@ -0,0 +1,9 @@
|
||||
#version 460
|
||||
#extension GL_EXT_ray_tracing : enable
|
||||
#pragma shader_stage(miss)
|
||||
|
||||
layout(location = 0) rayPayloadInEXT vec4 hitValue;
|
||||
|
||||
void main() {
|
||||
hitValue = vec4(0.2, 0.2, 0.2, 1.0);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"engine": {
|
||||
"scenes": {
|
||||
"start": "SS2",
|
||||
"start": "StartMenu",
|
||||
"meshes": { "interleaved": false },
|
||||
"matrix": { "reverseInfinite": false },
|
||||
"lights": { "enabled": false,
|
||||
|
||||
@ -28,6 +28,7 @@ namespace {
|
||||
}
|
||||
|
||||
void abrt( int sig ) {
|
||||
ext::ready = false;
|
||||
UF_MSG_ERROR("Abort detected");
|
||||
#if UF_ENV_DREAMCAST
|
||||
arch_stk_trace(1);
|
||||
@ -35,6 +36,7 @@ namespace {
|
||||
}
|
||||
|
||||
void segv( int sig ) {
|
||||
ext::ready = false;
|
||||
UF_MSG_ERROR("Segfault detected");
|
||||
#if UF_ENV_DREAMCAST
|
||||
arch_stk_trace(1);
|
||||
@ -74,7 +76,7 @@ int main(int argc, char** argv){
|
||||
try {
|
||||
#endif
|
||||
if ( uf::renderer::settings::experimental::dedicatedThread /*&& !uf::renderer::states::rebuild*/ ) {
|
||||
auto& thread = uf::thread::get("Aux");
|
||||
auto& thread = uf::thread::fetchWorker();
|
||||
uf::thread::queue(thread, [&]{
|
||||
ext::render();
|
||||
client::render();
|
||||
|
||||
7
debug.sh
7
debug.sh
@ -3,8 +3,5 @@ cd bin
|
||||
ARCH=$(cat ./exe/default/arch)
|
||||
CC=$(cat ./exe/default/cc)
|
||||
RENDERER=$(cat ./exe/default/renderer)
|
||||
cp ./exe/lib/$ARCH/*.dll .
|
||||
cp ./exe/lib/$ARCH/$CC/$RENDERER/*.dll .
|
||||
gdb ./exe/program.$ARCH.$CC.$RENDERER.exe
|
||||
rm *.dll
|
||||
|
||||
export PATH="$(pwd)/exe/lib/${ARCH}/:$(pwd)/exe/lib/${ARCH}/${CC}/${RENDERER}/:${PATH}"
|
||||
gdb ./exe/program.${ARCH}.${CC}.${RENDERER}.exe
|
||||
|
||||
@ -8,6 +8,7 @@ namespace ext {
|
||||
struct Device;
|
||||
|
||||
struct UF_API Buffer {
|
||||
bool aliased = false;
|
||||
ext::vulkan::Device* device = NULL;
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
@ -17,6 +18,7 @@ namespace ext {
|
||||
0
|
||||
};
|
||||
VkDeviceSize alignment = 0;
|
||||
size_t address = {};
|
||||
void* mapped = nullptr;
|
||||
|
||||
VkBufferUsageFlags usage = 0;
|
||||
@ -38,9 +40,12 @@ namespace ext {
|
||||
VkResult invalidate( VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0 );
|
||||
void allocate( VkBufferCreateInfo );
|
||||
|
||||
uint64_t getAddress();
|
||||
uint64_t getAddress() const;
|
||||
|
||||
// RAII
|
||||
~Buffer();
|
||||
void initialize( ext::vulkan::Device& device );
|
||||
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;
|
||||
void destroy();
|
||||
@ -48,6 +53,7 @@ namespace ext {
|
||||
void aliasBuffer( const Buffer& );
|
||||
};
|
||||
struct UF_API Buffers {
|
||||
size_t requestedAlignment{};
|
||||
uf::stl::vector<Buffer> buffers;
|
||||
Device* device = NULL;
|
||||
|
||||
@ -60,19 +66,12 @@ namespace ext {
|
||||
size_t initializeBuffer( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool = VK_DEFAULT_STAGE_BUFFERS );
|
||||
bool updateBuffer( const void*, VkDeviceSize, const Buffer&, bool = VK_DEFAULT_STAGE_BUFFERS ) const;
|
||||
|
||||
inline size_t initializeBuffer( void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (const void*) data, length, usage, memoryProperties, stage ); }
|
||||
template<typename T> inline size_t initializeBuffer( const T& data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (const void*) &data, length, usage, memoryProperties, stage ); }
|
||||
template<typename T> inline size_t initializeBuffer( const T& data, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (const void*) &data, static_cast<VkDeviceSize>(sizeof(T)), usage, memoryProperties, stage ); }
|
||||
// template<typename T> inline size_t initializeBuffer( const T* data, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (const void*) data, static_cast<VkDeviceSize>(sizeof(T)), usage, memoryProperties, stage ); }
|
||||
// template<typename T> inline size_t initializeBuffer( const T& data, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, bool stage = VK_DEFAULT_STAGE_BUFFERS ) { return initializeBuffer( (const void*) &data, static_cast<VkDeviceSize>(sizeof(T)), usage, memoryProperties, stage ); }
|
||||
|
||||
inline bool updateBuffer( const void* data, VkDeviceSize length, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( data, length, buffers.at(index), stage ); }
|
||||
inline bool updateBuffer( void* data, VkDeviceSize length, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) data, length, index, stage ); }
|
||||
inline bool updateBuffer( void* data, VkDeviceSize length, const Buffer& buffer, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) data, length, buffer, stage ); }
|
||||
|
||||
template<typename T> inline bool updateBuffer( const T& data, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) &data, static_cast<VkDeviceSize>(sizeof(T)), index, stage ); }
|
||||
template<typename T> inline bool updateBuffer( const T& data, VkDeviceSize length, size_t index = 0, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) &data, length, index, stage ); }
|
||||
|
||||
// template<typename T> inline bool updateBuffer( const T* data, const Buffer& buffer, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) data, static_cast<VkDeviceSize>(sizeof(T)), buffer, stage ); }
|
||||
template<typename T> inline bool updateBuffer( const T& data, const Buffer& buffer, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) &data, static_cast<VkDeviceSize>(sizeof(T)), buffer, stage ); }
|
||||
template<typename T> inline bool updateBuffer( const T& data, VkDeviceSize length, const Buffer& buffer, bool stage = VK_DEFAULT_STAGE_BUFFERS ) const { return updateBuffer( (const void*) &data, length, buffer, stage ); }
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -15,9 +15,6 @@ namespace ext {
|
||||
VkPhysicalDevice physicalDevice;
|
||||
VkDevice logicalDevice;
|
||||
struct {
|
||||
// uf::stl::unordered_map<std::thread::id, VkCommandPool> graphics;
|
||||
// uf::stl::unordered_map<std::thread::id, VkCommandPool> compute;
|
||||
// uf::stl::unordered_map<std::thread::id, VkCommandPool> transfer;
|
||||
uf::ThreadUnique<VkCommandPool> graphics;
|
||||
uf::ThreadUnique<VkCommandPool> compute;
|
||||
uf::ThreadUnique<VkCommandPool> transfer;
|
||||
@ -47,10 +44,6 @@ namespace ext {
|
||||
uf::stl::vector<VkQueueFamilyProperties> queueFamilyProperties;
|
||||
|
||||
struct {
|
||||
// uf::stl::unordered_map<std::thread::id,VkQueue> graphics;
|
||||
// uf::stl::unordered_map<std::thread::id,VkQueue> present;
|
||||
// uf::stl::unordered_map<std::thread::id,VkQueue> compute;
|
||||
// uf::stl::unordered_map<std::thread::id,VkQueue> transfer;
|
||||
uf::ThreadUnique<VkQueue> graphics;
|
||||
uf::ThreadUnique<VkQueue> present;
|
||||
uf::ThreadUnique<VkQueue> compute;
|
||||
@ -59,14 +52,12 @@ namespace ext {
|
||||
|
||||
uf::Window* window;
|
||||
|
||||
/*
|
||||
struct {
|
||||
VkFormat depth;
|
||||
VkFormat color;
|
||||
VkColorSpaceKHR space;
|
||||
} formats;
|
||||
*/
|
||||
|
||||
enum QueueEnum {
|
||||
GRAPHICS,
|
||||
PRESENT,
|
||||
COMPUTE,
|
||||
TRANSFER,
|
||||
};
|
||||
struct QueueFamilyIndices {
|
||||
uint32_t graphics;
|
||||
uint32_t present;
|
||||
@ -78,10 +69,12 @@ namespace ext {
|
||||
// helpers
|
||||
uint32_t getQueueFamilyIndex( VkQueueFlagBits queueFlags );
|
||||
uint32_t getMemoryType( uint32_t typeBits, VkMemoryPropertyFlags properties, VkBool32 *memTypeFound = nullptr );
|
||||
int rate( VkPhysicalDevice device );
|
||||
|
||||
VkCommandBuffer createCommandBuffer( VkCommandBufferLevel level, bool begin = false );
|
||||
VkCommandBuffer createCommandBuffer( VkCommandBufferLevel level, bool begin = true );
|
||||
VkCommandBuffer createCommandBuffer( VkCommandBufferLevel level, QueueEnum queue, bool begin = true );
|
||||
|
||||
void flushCommandBuffer( VkCommandBuffer commandBuffer, bool free = true );
|
||||
void flushCommandBuffer( VkCommandBuffer commandBuffer, QueueEnum queue, bool free = true );
|
||||
|
||||
VkResult createBuffer(
|
||||
VkBufferUsageFlags usage,
|
||||
@ -99,12 +92,6 @@ namespace ext {
|
||||
const void* data = nullptr
|
||||
);
|
||||
|
||||
enum QueueEnum {
|
||||
GRAPHICS,
|
||||
PRESENT,
|
||||
COMPUTE,
|
||||
TRANSFER,
|
||||
};
|
||||
VkQueue& getQueue( QueueEnum );
|
||||
VkCommandPool& getCommandPool( QueueEnum );
|
||||
VkQueue& getQueue( QueueEnum, std::thread::id );
|
||||
|
||||
@ -67,6 +67,9 @@ namespace ext {
|
||||
static const type_t GEOMETRY = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||
static const type_t FRAGMENT = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
static const type_t COMPUTE = VK_SHADER_STAGE_COMPUTE_BIT;
|
||||
static const type_t RAY_GEN = VK_SHADER_STAGE_RAYGEN_BIT_KHR;
|
||||
static const type_t RAY_MISS = VK_SHADER_STAGE_MISS_BIT_KHR;
|
||||
static const type_t RAY_HIT = VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR;
|
||||
static const type_t ALL_GRAPHICS = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||
static const type_t ALL = VK_SHADER_STAGE_ALL;
|
||||
}
|
||||
@ -129,6 +132,9 @@ namespace ext {
|
||||
static const type_t INDEX = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
||||
static const type_t VERTEX = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
||||
static const type_t INDIRECT = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT;
|
||||
static const type_t ACCELERATION_STRUCTURE = VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR;
|
||||
static const type_t ADDRESS = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
static const type_t BINDING_TABLE = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR;
|
||||
|
||||
static const type_t STREAM = {};
|
||||
static const type_t STATIC = {};
|
||||
|
||||
@ -23,6 +23,8 @@ namespace ext {
|
||||
VkDescriptorSet descriptorSet = VK_NULL_HANDLE;
|
||||
GraphicDescriptor descriptor = {};
|
||||
|
||||
uf::stl::vector<VkStridedDeviceAddressRegionKHR> sbtEntries;
|
||||
|
||||
struct {
|
||||
uf::Serializer json;
|
||||
|
||||
@ -76,12 +78,20 @@ namespace ext {
|
||||
bool initialized = false;
|
||||
bool process = true;
|
||||
Material material = {};
|
||||
uf::stl::unordered_map<GraphicDescriptor::hash_t, Pipeline> pipelines;
|
||||
uf::stl::unordered_map<GraphicDescriptor, Pipeline> pipelines;
|
||||
|
||||
struct {
|
||||
uf::stl::unordered_map<uf::stl::string, size_t> buffers;
|
||||
} metadata;
|
||||
|
||||
struct {
|
||||
struct {
|
||||
VkAccelerationStructureKHR handle;
|
||||
size_t deviceAddress;
|
||||
Buffer buffer;
|
||||
} top, bottom;
|
||||
} accelerationStructures;
|
||||
|
||||
~Graphic();
|
||||
void initialize( const uf::stl::string& = "" );
|
||||
void destroy();
|
||||
|
||||
@ -65,6 +65,7 @@ namespace ext {
|
||||
bool tryMutex( std::thread::id = std::this_thread::get_id() );
|
||||
void unlockMutex( std::thread::id = std::this_thread::get_id() );
|
||||
std::lock_guard<std::mutex> guardMutex( std::thread::id = std::this_thread::get_id() );
|
||||
void cleanupCommands( std::thread::id = std::this_thread::get_id() );
|
||||
|
||||
virtual ~RenderMode();
|
||||
// RAII
|
||||
|
||||
31
engine/inc/uf/ext/vulkan/rendermodes/raytrace.h
Normal file
31
engine/inc/uf/ext/vulkan/rendermodes/raytrace.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <uf/ext/vulkan/rendermode.h>
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
|
||||
namespace ext {
|
||||
namespace vulkan {
|
||||
struct UF_API RayTraceRenderMode : public ext::vulkan::RenderMode {
|
||||
ext::vulkan::Graphic blitter;
|
||||
|
||||
//
|
||||
const uf::stl::string getTarget() const;
|
||||
void setTarget( const uf::stl::string& );
|
||||
|
||||
//
|
||||
virtual const uf::stl::string getType() const;
|
||||
virtual const size_t blitters() const;
|
||||
virtual ext::vulkan::Graphic* getBlitter(size_t = 0);
|
||||
virtual uf::stl::vector<ext::vulkan::Graphic*> getBlitters();
|
||||
|
||||
virtual GraphicDescriptor bindGraphicDescriptor( const GraphicDescriptor&, size_t = 0 );
|
||||
|
||||
virtual void createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics );
|
||||
virtual void initialize( Device& device );
|
||||
virtual void tick();
|
||||
virtual void destroy();
|
||||
virtual void render();
|
||||
virtual void pipelineBarrier( VkCommandBuffer, uint8_t = -1 );
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -68,6 +68,13 @@ namespace ext {
|
||||
uint32_t size = 0;
|
||||
// int32_t buffer = -1;
|
||||
};
|
||||
struct AccelerationStructure {
|
||||
uf::stl::string name = "";
|
||||
uint32_t index = 0;
|
||||
uint32_t binding = 0;
|
||||
uint32_t size = 0;
|
||||
// int32_t buffer = -1;
|
||||
};
|
||||
struct PushConstant {
|
||||
uf::stl::string name = "";
|
||||
uint32_t index = 0;
|
||||
@ -90,6 +97,7 @@ namespace ext {
|
||||
uf::stl::unordered_map<uf::stl::string, InOut> outputs;
|
||||
uf::stl::unordered_map<uf::stl::string, Uniform> uniforms;
|
||||
uf::stl::unordered_map<uf::stl::string, Storage> storage;
|
||||
uf::stl::unordered_map<uf::stl::string, AccelerationStructure> accelerationStructure;
|
||||
uf::stl::unordered_map<uf::stl::string, PushConstant> pushConstants;
|
||||
uf::stl::unordered_map<uf::stl::string, SpecializationConstants> specializationConstants;
|
||||
} definitions;
|
||||
|
||||
@ -14,5 +14,5 @@
|
||||
#define VK_CHECK_RESULT(f) { VkResult res = (f); if ( res != VK_SUCCESS ) UF_EXCEPTION(ext::vulkan::errorString( res )); }
|
||||
|
||||
#define VK_FLAGS_NONE 0
|
||||
#define VK_DEFAULT_FENCE_TIMEOUT 100000000000
|
||||
#define VK_DEFAULT_FENCE_TIMEOUT 5000000000
|
||||
#define VK_DEFAULT_STAGE_BUFFERS 1
|
||||
@ -10,6 +10,19 @@
|
||||
|
||||
namespace ext {
|
||||
namespace vulkan {
|
||||
#if 1
|
||||
extern UF_API PFN_vkGetBufferDeviceAddressKHR vkGetBufferDeviceAddressKHR;
|
||||
extern UF_API PFN_vkCreateAccelerationStructureKHR vkCreateAccelerationStructureKHR;
|
||||
extern UF_API PFN_vkDestroyAccelerationStructureKHR vkDestroyAccelerationStructureKHR;
|
||||
extern UF_API PFN_vkGetAccelerationStructureBuildSizesKHR vkGetAccelerationStructureBuildSizesKHR;
|
||||
extern UF_API PFN_vkGetAccelerationStructureDeviceAddressKHR vkGetAccelerationStructureDeviceAddressKHR;
|
||||
extern UF_API PFN_vkCmdBuildAccelerationStructuresKHR vkCmdBuildAccelerationStructuresKHR;
|
||||
extern UF_API PFN_vkBuildAccelerationStructuresKHR vkBuildAccelerationStructuresKHR;
|
||||
extern UF_API PFN_vkCmdTraceRaysKHR vkCmdTraceRaysKHR;
|
||||
extern UF_API PFN_vkGetRayTracingShaderGroupHandlesKHR vkGetRayTracingShaderGroupHandlesKHR;
|
||||
extern UF_API PFN_vkCreateRayTracingPipelinesKHR vkCreateRayTracingPipelinesKHR;
|
||||
#endif
|
||||
|
||||
VkResult CreateDebugUtilsMessengerEXT(
|
||||
VkInstance instance,
|
||||
const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
@ -55,6 +68,7 @@ namespace ext {
|
||||
extern UF_API bool dedicatedThread;
|
||||
extern UF_API bool rebuildOnTickBegin;
|
||||
extern UF_API bool batchQueueSubmissions;
|
||||
extern UF_API bool enableMultiGPU;
|
||||
}
|
||||
|
||||
namespace invariant {
|
||||
|
||||
@ -125,6 +125,10 @@
|
||||
#define LENGTH_OF(X) *(&X + 1) - X
|
||||
#define FOR_ARRAY(X) for ( auto i = 0; i < LENGTH_OF(X); ++i )
|
||||
|
||||
#define ALIGNED_SIZE(V, A) ((V + A - 1) & ~(A - 1))
|
||||
|
||||
#define UF_MSG_PEEK(X) #X << ": " << X
|
||||
|
||||
#if UF_ENV_DREAMCAST
|
||||
#define DC_STATS() {\
|
||||
UF_MSG_DEBUG(spec::dreamcast::malloc_stats());\
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
#include <uf/ext/vulkan/rendermodes/rendertarget.h>
|
||||
#include <uf/ext/vulkan/rendermodes/deferred.h>
|
||||
#include <uf/ext/vulkan/rendermodes/raytrace.h>
|
||||
#include <uf/ext/vulkan/rendertarget.h>
|
||||
|
||||
namespace spec {
|
||||
|
||||
11
engine/inc/uf/utils/math/hash.h
Normal file
11
engine/inc/uf/utils/math/hash.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace uf {
|
||||
inline void hash(std::size_t& seed) { }
|
||||
|
||||
template <typename T, typename... Rest>
|
||||
inline void hash(std::size_t& seed, const T& v, Rest... rest) {
|
||||
seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
hash(seed, rest...);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <uf/config.h>
|
||||
#include <cstdint>
|
||||
#include "hash.h"
|
||||
|
||||
#if UF_ENV_DREAMCAST
|
||||
#include "sh4.h"
|
||||
|
||||
@ -257,12 +257,8 @@ namespace uf {
|
||||
namespace ext {
|
||||
namespace RENDERER {
|
||||
struct UF_API GraphicDescriptor {
|
||||
#if UF_GRAPHIC_DESCRIPTOR_USE_STRING
|
||||
typedef uf::stl::string hash_t;
|
||||
#else
|
||||
typedef size_t hash_t;
|
||||
#endif
|
||||
|
||||
|
||||
uf::stl::string renderMode = "";
|
||||
uf::stl::string pipeline = "";
|
||||
|
||||
@ -273,6 +269,8 @@ namespace ext {
|
||||
uf::Mesh::Input vertex, index, instance, indirect;
|
||||
size_t bufferOffset = 0;
|
||||
pod::Vector3ui dispatch = { 0, 0, 0 };
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
} inputs;
|
||||
|
||||
ext::RENDERER::enums::PrimitiveTopology::type_t topology = ext::RENDERER::enums::PrimitiveTopology::TRIANGLE_LIST;
|
||||
@ -303,6 +301,13 @@ namespace ext {
|
||||
}
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<ext::RENDERER::GraphicDescriptor> {
|
||||
size_t operator()(const ext::RENDERER::GraphicDescriptor& descriptor) const { return descriptor.hash(); }
|
||||
};
|
||||
}
|
||||
|
||||
#undef UF_RENDERER
|
||||
#define UF_VERTEX_DESCRIPTION( TYPE, FORMAT, ATTRIBUTE ) {\
|
||||
.offset = offsetof(TYPE, ATTRIBUTE),\
|
||||
|
||||
@ -26,6 +26,7 @@ namespace uf {
|
||||
bool tryMutex( id_t id = std::this_thread::get_id() );
|
||||
void unlockMutex( id_t id = std::this_thread::get_id() );
|
||||
std::lock_guard<std::mutex> guardMutex( id_t id = std::this_thread::get_id() );
|
||||
void cleanup( id_t id = std::this_thread::get_id() );
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,20 @@ std::lock_guard<std::mutex> uf::ThreadUnique<T>::guardMutex( id_t id ) {
|
||||
return std::lock_guard<std::mutex>(*m_mutex_container[id]);
|
||||
}
|
||||
template<typename T>
|
||||
void uf::ThreadUnique<T>::cleanup( id_t id ) {
|
||||
for ( auto it = m_container.begin(); it != m_container.end(); ) {
|
||||
if ( it->first == id ) ++it;
|
||||
else it = m_container.erase(it);
|
||||
}
|
||||
for ( auto it = m_mutex_container.begin(); it != m_mutex_container.end(); ) {
|
||||
if ( it->first == id ) ++it;
|
||||
else {
|
||||
delete it->second;
|
||||
it = m_mutex_container.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
typename uf::ThreadUnique<T>::container_t& uf::ThreadUnique<T>::container() {
|
||||
return m_container;
|
||||
}
|
||||
@ -16,6 +16,13 @@
|
||||
#include <functional>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace uf {
|
||||
namespace thread {
|
||||
extern UF_API uf::stl::string workerThreadName;
|
||||
extern UF_API uf::stl::string mainThreadName;
|
||||
}
|
||||
}
|
||||
|
||||
namespace pod {
|
||||
struct UF_API Thread {
|
||||
typedef std::function<void()> function_t;
|
||||
@ -28,7 +35,10 @@ namespace pod {
|
||||
bool running, terminates;
|
||||
|
||||
std::mutex* mutex;
|
||||
std::condition_variable condition;
|
||||
struct {
|
||||
std::condition_variable queued;
|
||||
std::condition_variable finished;
|
||||
} conditions;
|
||||
std::thread thread;
|
||||
|
||||
pod::Thread::queue_t queue;
|
||||
@ -38,7 +48,7 @@ namespace pod {
|
||||
uint affinity = 0;
|
||||
|
||||
struct UF_API Tasks {
|
||||
uf::stl::string name = "Aux";
|
||||
uf::stl::string name = uf::thread::workerThreadName;
|
||||
bool waits = true;
|
||||
|
||||
pod::Thread::queue_t container;
|
||||
@ -60,8 +70,9 @@ namespace uf {
|
||||
extern UF_API bool async;
|
||||
|
||||
/* Easy to use async helper functions */
|
||||
pod::Thread& UF_API fetchWorker( const uf::stl::string& name = "Aux" );
|
||||
pod::Thread::Tasks UF_API schedule( const uf::stl::string& name = "Aux", bool waits = true );
|
||||
pod::Thread& UF_API fetchWorker( const uf::stl::string& name = uf::thread::workerThreadName );
|
||||
pod::Thread::Tasks UF_API schedule( bool multithread, bool waits = true );
|
||||
pod::Thread::Tasks UF_API schedule( const uf::stl::string& name = uf::thread::workerThreadName, bool waits = true );
|
||||
void UF_API execute( pod::Thread::Tasks& tasks );
|
||||
|
||||
/* Acts on global threads */
|
||||
|
||||
@ -50,7 +50,7 @@ uf::Asset uf::Asset::masterAssetLoader;
|
||||
bool uf::Asset::assertionLoad = true;
|
||||
|
||||
void uf::Asset::processQueue() {
|
||||
uf::thread::queue([&]{
|
||||
// uf::thread::queue([&]{
|
||||
mutex.lock();
|
||||
auto jobs = std::move(this->getComponent<std::queue<Job>>());
|
||||
while ( !jobs.empty() ) {
|
||||
@ -68,7 +68,7 @@ void uf::Asset::processQueue() {
|
||||
if ( callback != "" && filename != "" ) uf::hooks.call(callback, payload);
|
||||
}
|
||||
mutex.unlock();
|
||||
});
|
||||
// });
|
||||
}
|
||||
void uf::Asset::cache( const uf::stl::string& callback, const uf::Asset::Payload& payload ) {
|
||||
mutex.lock();
|
||||
|
||||
@ -307,9 +307,9 @@ pod::Graph uf::graph::load( const uf::stl::string& filename, const uf::Serialize
|
||||
graph.metadata = metadata; // serializer["metadata"];
|
||||
|
||||
#if UF_GRAPH_LOAD_MULTITHREAD
|
||||
auto tasks = uf::thread::schedule("Async");
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
#else
|
||||
auto tasks = uf::thread::schedule("Main");
|
||||
auto tasks = uf::thread::schedule(false);
|
||||
#endif
|
||||
|
||||
tasks.queue([&]{
|
||||
|
||||
@ -262,9 +262,9 @@ uf::stl::string uf::graph::save( const pod::Graph& graph, const uf::stl::string&
|
||||
#endif
|
||||
|
||||
#if UF_GRAPH_LOAD_MULTITHREAD
|
||||
auto tasks = uf::thread::schedule("Async");
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
#else
|
||||
auto tasks = uf::thread::schedule("Main");
|
||||
auto tasks = uf::thread::schedule(false);
|
||||
#endif
|
||||
tasks.queue([&]{
|
||||
ext::json::reserve( serializer["instances"], graph.instances.size() );
|
||||
|
||||
@ -1149,7 +1149,7 @@ void uf::graph::tick() {
|
||||
::newGraphAdded = false;
|
||||
}
|
||||
}
|
||||
void uf::graph::render() {
|
||||
void uf::graph::render() {
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
@ -1163,10 +1163,10 @@ void uf::graph::render() {
|
||||
uf::graph::storage.buffers.camera.update( (const void*) &camera.data().viewport, sizeof(pod::Camera::Viewports) );
|
||||
}
|
||||
#endif
|
||||
#if UF_USE_VULKAN
|
||||
auto* renderMode = uf::renderer::getCurrentRenderMode();
|
||||
if ( !renderMode ) return;
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
for ( auto& buffer : renderMode->buffers ) {
|
||||
if ( !(buffer.usage & uf::renderer::enums::Buffer::UNIFORM) ) continue;
|
||||
if ( buffer.allocationInfo.size != sizeof(pod::Camera::Viewports) ) continue;
|
||||
|
||||
@ -143,14 +143,14 @@ void uf::scene::tick() {
|
||||
auto graph = scene.getGraph(true);
|
||||
#if 1
|
||||
for ( auto entity : graph ) entity->tick();
|
||||
auto& tasks = metadata.tasks;
|
||||
#else
|
||||
auto& tasks = metadata.tasks;
|
||||
pod::Thread::Tasks tasks = metadata.tasks;
|
||||
tasks.queue([&]{
|
||||
for ( auto entity : graph ) entity->tick();
|
||||
});
|
||||
#endif
|
||||
uf::thread::execute( tasks );
|
||||
#endif
|
||||
}
|
||||
void uf::scene::render() {
|
||||
if ( scenes.empty() ) return;
|
||||
|
||||
@ -205,7 +205,7 @@ void UF_API ext::opengl::initialize() {
|
||||
|
||||
uf::graph::initialize();
|
||||
|
||||
auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording ? "Aux" : "Main");
|
||||
auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording);
|
||||
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
|
||||
tasks.queue([&]{
|
||||
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
|
||||
@ -377,7 +377,7 @@ void UF_API ext::opengl::tick(){
|
||||
renderMode->tick();
|
||||
}
|
||||
|
||||
auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording ? "Aux" : "Main");
|
||||
auto tasks = uf::thread::schedule(settings::invariant::multithreadedRecording);
|
||||
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
|
||||
if ( ext::opengl::states::rebuild || renderMode->rebuild ) tasks.queue([&]{
|
||||
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
|
||||
|
||||
@ -22,11 +22,13 @@ void ext::vulkan::Buffer::aliasBuffer( const ext::vulkan::Buffer& buffer ) {
|
||||
.allocationInfo = buffer.allocationInfo,
|
||||
};
|
||||
*/
|
||||
this->device = NULL;
|
||||
this->aliased = true;
|
||||
this->device = buffer.device;
|
||||
this->buffer = buffer.buffer;
|
||||
this->memory = buffer.memory;
|
||||
this->descriptor = buffer.descriptor;
|
||||
this->alignment = buffer.alignment;
|
||||
this->address = buffer.address;
|
||||
this->mapped = buffer.mapped;
|
||||
this->usage = buffer.usage;
|
||||
this->memoryProperties = buffer.memoryProperties;
|
||||
@ -84,18 +86,32 @@ void ext::vulkan::Buffer::allocate( VkBufferCreateInfo bufferCreateInfo ) {
|
||||
allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
|
||||
}
|
||||
|
||||
vmaCreateBuffer( allocator, &bufferCreateInfo, &allocCreateInfo, &buffer, &allocation, &allocationInfo );
|
||||
vmaCreateBufferWithAlignment( allocator, &bufferCreateInfo, &allocCreateInfo, alignment, &buffer, &allocation, &allocationInfo );
|
||||
}
|
||||
|
||||
size_t ext::vulkan::Buffer::getAddress() {
|
||||
VkBufferDeviceAddressInfoKHR info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
info.buffer = buffer;
|
||||
return (this->address = vkGetBufferDeviceAddressKHR(this->device ? *this->device : ext::vulkan::device, &info));
|
||||
}
|
||||
size_t ext::vulkan::Buffer::getAddress() const {
|
||||
VkBufferDeviceAddressInfoKHR info{};
|
||||
info.sType = VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO;
|
||||
info.buffer = buffer;
|
||||
return vkGetBufferDeviceAddressKHR(this->device ? *this->device : ext::vulkan::device, &info);
|
||||
}
|
||||
|
||||
// RAII
|
||||
ext::vulkan::Buffer::~Buffer() {
|
||||
// this->destroy();
|
||||
}
|
||||
void ext::vulkan::Buffer::initialize( ext::vulkan::Device& device ) {
|
||||
void ext::vulkan::Buffer::initialize( ext::vulkan::Device& device, size_t alignment ) {
|
||||
this->device = &device;
|
||||
this->alignment = alignment;
|
||||
}
|
||||
void ext::vulkan::Buffer::destroy() {
|
||||
if ( !device ) return;
|
||||
if ( !device || aliased ) return;
|
||||
|
||||
if ( buffer ) {
|
||||
vmaDestroyBuffer( allocator, buffer, allocation );
|
||||
@ -145,12 +161,12 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length, bool st
|
||||
);
|
||||
|
||||
// Copy to staging buffer
|
||||
VkCommandBuffer copyCommand = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer copyCommand = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::TRANSFER);
|
||||
VkBufferCopy region = {};
|
||||
region.size = length;
|
||||
vkCmdCopyBuffer(copyCommand, staging.buffer, buffer, 1, ®ion);
|
||||
|
||||
device->flushCommandBuffer(copyCommand, true);
|
||||
device->flushCommandBuffer(copyCommand, Device::QueueEnum::TRANSFER);
|
||||
staging.destroy();
|
||||
return false;
|
||||
}
|
||||
@ -174,7 +190,7 @@ void ext::vulkan::Buffers::destroy() {
|
||||
size_t ext::vulkan::Buffers::initializeBuffer( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, bool stage ) {
|
||||
size_t index = buffers.size();
|
||||
auto& buffer = buffers.emplace_back();
|
||||
buffer.initialize( *device );
|
||||
buffer.initialize( *device, requestedAlignment );
|
||||
buffer.initialize( data, length, usage, memoryProperties, stage );
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -15,6 +15,171 @@
|
||||
#define UF_MSG_VALIDATION(X) if ( ext::vulkan::settings::validation ) UF_MSG(X, " VULKAN ");
|
||||
|
||||
namespace {
|
||||
struct DeviceInfo {
|
||||
VkPhysicalDevice handle = VK_NULL_HANDLE;
|
||||
VkPhysicalDeviceProperties properties;
|
||||
VkPhysicalDeviceFeatures features;
|
||||
size_t score;
|
||||
};
|
||||
|
||||
::DeviceInfo rate( ext::vulkan::Device& device, VkPhysicalDevice handle ) {
|
||||
::DeviceInfo deviceInfo{ .handle = handle };
|
||||
|
||||
auto& physicalDevice = deviceInfo.handle;
|
||||
auto& deviceProperties = deviceInfo.properties;
|
||||
auto& deviceFeatures = deviceInfo.features;
|
||||
auto& score = deviceInfo.score;
|
||||
|
||||
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
||||
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
|
||||
|
||||
// Discrete GPUs have a significant performance advantage
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score += 1000;
|
||||
{
|
||||
score += deviceProperties.limits.maxImageDimension1D;
|
||||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
score += deviceProperties.limits.maxImageDimension3D;
|
||||
score += deviceProperties.limits.maxImageDimensionCube;
|
||||
score += deviceProperties.limits.maxImageArrayLayers;
|
||||
score += deviceProperties.limits.maxTexelBufferElements;
|
||||
score += deviceProperties.limits.maxUniformBufferRange;
|
||||
score += deviceProperties.limits.maxStorageBufferRange;
|
||||
score += deviceProperties.limits.maxPushConstantsSize;
|
||||
score += deviceProperties.limits.maxMemoryAllocationCount;
|
||||
score += deviceProperties.limits.maxSamplerAllocationCount;
|
||||
score += deviceProperties.limits.bufferImageGranularity;
|
||||
score += deviceProperties.limits.sparseAddressSpaceSize;
|
||||
score += deviceProperties.limits.maxBoundDescriptorSets;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorSamplers;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorUniformBuffers;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorStorageBuffers;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorSampledImages;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorStorageImages;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorInputAttachments;
|
||||
score += deviceProperties.limits.maxPerStageResources;
|
||||
score += deviceProperties.limits.maxDescriptorSetSamplers;
|
||||
score += deviceProperties.limits.maxDescriptorSetUniformBuffers;
|
||||
score += deviceProperties.limits.maxDescriptorSetUniformBuffersDynamic;
|
||||
score += deviceProperties.limits.maxDescriptorSetStorageBuffers;
|
||||
score += deviceProperties.limits.maxDescriptorSetStorageBuffersDynamic;
|
||||
score += deviceProperties.limits.maxDescriptorSetSampledImages;
|
||||
score += deviceProperties.limits.maxDescriptorSetStorageImages;
|
||||
score += deviceProperties.limits.maxDescriptorSetInputAttachments;
|
||||
score += deviceProperties.limits.maxVertexInputAttributes;
|
||||
score += deviceProperties.limits.maxVertexInputBindings;
|
||||
score += deviceProperties.limits.maxVertexInputAttributeOffset;
|
||||
score += deviceProperties.limits.maxVertexInputBindingStride;
|
||||
score += deviceProperties.limits.maxVertexOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationGenerationLevel;
|
||||
score += deviceProperties.limits.maxTessellationPatchSize;
|
||||
score += deviceProperties.limits.maxTessellationControlPerVertexInputComponents;
|
||||
score += deviceProperties.limits.maxTessellationControlPerVertexOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationControlPerPatchOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationControlTotalOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationEvaluationInputComponents;
|
||||
score += deviceProperties.limits.maxTessellationEvaluationOutputComponents;
|
||||
score += deviceProperties.limits.maxGeometryShaderInvocations;
|
||||
score += deviceProperties.limits.maxGeometryInputComponents;
|
||||
score += deviceProperties.limits.maxGeometryOutputComponents;
|
||||
score += deviceProperties.limits.maxGeometryOutputVertices;
|
||||
score += deviceProperties.limits.maxGeometryTotalOutputComponents;
|
||||
score += deviceProperties.limits.maxFragmentInputComponents;
|
||||
score += deviceProperties.limits.maxFragmentOutputAttachments;
|
||||
score += deviceProperties.limits.maxFragmentDualSrcAttachments;
|
||||
score += deviceProperties.limits.maxFragmentCombinedOutputResources;
|
||||
score += deviceProperties.limits.maxComputeSharedMemorySize;
|
||||
score += deviceProperties.limits.maxComputeWorkGroupInvocations;
|
||||
score += deviceProperties.limits.subPixelPrecisionBits;
|
||||
score += deviceProperties.limits.subTexelPrecisionBits;
|
||||
score += deviceProperties.limits.mipmapPrecisionBits;
|
||||
score += deviceProperties.limits.maxDrawIndexedIndexValue;
|
||||
score += deviceProperties.limits.maxDrawIndirectCount;
|
||||
score += deviceProperties.limits.maxSamplerLodBias;
|
||||
score += deviceProperties.limits.maxSamplerAnisotropy;
|
||||
score += deviceProperties.limits.maxViewports;
|
||||
score += deviceProperties.limits.viewportSubPixelBits;
|
||||
score += deviceProperties.limits.minMemoryMapAlignment;
|
||||
score += deviceProperties.limits.minTexelBufferOffsetAlignment;
|
||||
score += deviceProperties.limits.minUniformBufferOffsetAlignment;
|
||||
score += deviceProperties.limits.minStorageBufferOffsetAlignment;
|
||||
score += deviceProperties.limits.minTexelOffset;
|
||||
score += deviceProperties.limits.maxTexelOffset;
|
||||
score += deviceProperties.limits.minTexelGatherOffset;
|
||||
score += deviceProperties.limits.maxTexelGatherOffset;
|
||||
score += deviceProperties.limits.minInterpolationOffset;
|
||||
score += deviceProperties.limits.maxInterpolationOffset;
|
||||
score += deviceProperties.limits.subPixelInterpolationOffsetBits;
|
||||
score += deviceProperties.limits.maxFramebufferWidth;
|
||||
score += deviceProperties.limits.maxFramebufferHeight;
|
||||
score += deviceProperties.limits.maxFramebufferLayers;
|
||||
score += deviceProperties.limits.framebufferColorSampleCounts;
|
||||
score += deviceProperties.limits.framebufferDepthSampleCounts;
|
||||
score += deviceProperties.limits.framebufferStencilSampleCounts;
|
||||
score += deviceProperties.limits.framebufferNoAttachmentsSampleCounts;
|
||||
score += deviceProperties.limits.maxColorAttachments;
|
||||
score += deviceProperties.limits.sampledImageColorSampleCounts;
|
||||
score += deviceProperties.limits.sampledImageIntegerSampleCounts;
|
||||
score += deviceProperties.limits.sampledImageDepthSampleCounts;
|
||||
score += deviceProperties.limits.sampledImageStencilSampleCounts;
|
||||
score += deviceProperties.limits.storageImageSampleCounts;
|
||||
score += deviceProperties.limits.maxSampleMaskWords;
|
||||
score += deviceProperties.limits.timestampComputeAndGraphics;
|
||||
score += deviceProperties.limits.timestampPeriod;
|
||||
score += deviceProperties.limits.maxClipDistances;
|
||||
score += deviceProperties.limits.maxCullDistances;
|
||||
score += deviceProperties.limits.maxCombinedClipAndCullDistances;
|
||||
score += deviceProperties.limits.discreteQueuePriorities;
|
||||
score += deviceProperties.limits.pointSizeGranularity;
|
||||
score += deviceProperties.limits.lineWidthGranularity;
|
||||
score += deviceProperties.limits.strictLines;
|
||||
score += deviceProperties.limits.standardSampleLocations;
|
||||
score += deviceProperties.limits.optimalBufferCopyOffsetAlignment;
|
||||
score += deviceProperties.limits.optimalBufferCopyRowPitchAlignment;
|
||||
score += deviceProperties.limits.nonCoherentAtomSize;
|
||||
}
|
||||
// Application can't function without geometry shaders
|
||||
if ( !deviceFeatures.geometryShader ) return deviceInfo;
|
||||
//
|
||||
{
|
||||
const uf::stl::vector<const char*> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties( physicalDevice, nullptr, &extensionCount, nullptr );
|
||||
uf::stl::vector<VkExtensionProperties> availableExtensions( extensionCount );
|
||||
vkEnumerateDeviceExtensionProperties( physicalDevice, nullptr, &extensionCount, availableExtensions.data() );
|
||||
std::set<uf::stl::string> requiredExtensions( deviceExtensions.begin(), deviceExtensions.end() );
|
||||
|
||||
for ( const auto& extension : availableExtensions )
|
||||
requiredExtensions.erase( extension.extensionName );
|
||||
|
||||
if ( !requiredExtensions.empty() ) return deviceInfo;
|
||||
}
|
||||
//
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
uf::stl::vector<VkSurfaceFormatKHR> formats;
|
||||
uf::stl::vector<VkPresentModeKHR> presentModes;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR( physicalDevice, device.surface, &capabilities );
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, device.surface, &formatCount, nullptr);
|
||||
if ( formatCount != 0 ) {
|
||||
formats.resize( formatCount );
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR( physicalDevice, device.surface, &formatCount, formats.data() );
|
||||
}
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, device.surface, &presentModeCount, nullptr );
|
||||
if ( presentModeCount != 0 ) {
|
||||
presentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR( physicalDevice, device.surface, &presentModeCount, presentModes.data() );
|
||||
}
|
||||
if ( formats.empty() || presentModes.empty() ) return deviceInfo;
|
||||
}
|
||||
return deviceInfo;
|
||||
}
|
||||
|
||||
#if UF_USE_OPENVR
|
||||
void VRInstanceExtensions( uf::stl::vector<uf::stl::string>& requested ) {
|
||||
if ( !vr::VRCompositor() ) return;
|
||||
@ -255,166 +420,11 @@ uint32_t ext::vulkan::Device::getMemoryType( uint32_t typeBits, VkMemoryProperty
|
||||
UF_EXCEPTION("Vulkan error: could not find a matching memory type");
|
||||
}
|
||||
|
||||
int ext::vulkan::Device::rate( VkPhysicalDevice device ) {
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
int score = 0;
|
||||
// Discrete GPUs have a significant performance advantage
|
||||
if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) score += 1000;
|
||||
{
|
||||
score += deviceProperties.limits.maxImageDimension1D;
|
||||
score += deviceProperties.limits.maxImageDimension2D;
|
||||
score += deviceProperties.limits.maxImageDimension3D;
|
||||
score += deviceProperties.limits.maxImageDimensionCube;
|
||||
score += deviceProperties.limits.maxImageArrayLayers;
|
||||
score += deviceProperties.limits.maxTexelBufferElements;
|
||||
score += deviceProperties.limits.maxUniformBufferRange;
|
||||
score += deviceProperties.limits.maxStorageBufferRange;
|
||||
score += deviceProperties.limits.maxPushConstantsSize;
|
||||
score += deviceProperties.limits.maxMemoryAllocationCount;
|
||||
score += deviceProperties.limits.maxSamplerAllocationCount;
|
||||
score += deviceProperties.limits.bufferImageGranularity;
|
||||
score += deviceProperties.limits.sparseAddressSpaceSize;
|
||||
score += deviceProperties.limits.maxBoundDescriptorSets;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorSamplers;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorUniformBuffers;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorStorageBuffers;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorSampledImages;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorStorageImages;
|
||||
score += deviceProperties.limits.maxPerStageDescriptorInputAttachments;
|
||||
score += deviceProperties.limits.maxPerStageResources;
|
||||
score += deviceProperties.limits.maxDescriptorSetSamplers;
|
||||
score += deviceProperties.limits.maxDescriptorSetUniformBuffers;
|
||||
score += deviceProperties.limits.maxDescriptorSetUniformBuffersDynamic;
|
||||
score += deviceProperties.limits.maxDescriptorSetStorageBuffers;
|
||||
score += deviceProperties.limits.maxDescriptorSetStorageBuffersDynamic;
|
||||
score += deviceProperties.limits.maxDescriptorSetSampledImages;
|
||||
score += deviceProperties.limits.maxDescriptorSetStorageImages;
|
||||
score += deviceProperties.limits.maxDescriptorSetInputAttachments;
|
||||
score += deviceProperties.limits.maxVertexInputAttributes;
|
||||
score += deviceProperties.limits.maxVertexInputBindings;
|
||||
score += deviceProperties.limits.maxVertexInputAttributeOffset;
|
||||
score += deviceProperties.limits.maxVertexInputBindingStride;
|
||||
score += deviceProperties.limits.maxVertexOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationGenerationLevel;
|
||||
score += deviceProperties.limits.maxTessellationPatchSize;
|
||||
score += deviceProperties.limits.maxTessellationControlPerVertexInputComponents;
|
||||
score += deviceProperties.limits.maxTessellationControlPerVertexOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationControlPerPatchOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationControlTotalOutputComponents;
|
||||
score += deviceProperties.limits.maxTessellationEvaluationInputComponents;
|
||||
score += deviceProperties.limits.maxTessellationEvaluationOutputComponents;
|
||||
score += deviceProperties.limits.maxGeometryShaderInvocations;
|
||||
score += deviceProperties.limits.maxGeometryInputComponents;
|
||||
score += deviceProperties.limits.maxGeometryOutputComponents;
|
||||
score += deviceProperties.limits.maxGeometryOutputVertices;
|
||||
score += deviceProperties.limits.maxGeometryTotalOutputComponents;
|
||||
score += deviceProperties.limits.maxFragmentInputComponents;
|
||||
score += deviceProperties.limits.maxFragmentOutputAttachments;
|
||||
score += deviceProperties.limits.maxFragmentDualSrcAttachments;
|
||||
score += deviceProperties.limits.maxFragmentCombinedOutputResources;
|
||||
score += deviceProperties.limits.maxComputeSharedMemorySize;
|
||||
score += deviceProperties.limits.maxComputeWorkGroupInvocations;
|
||||
score += deviceProperties.limits.subPixelPrecisionBits;
|
||||
score += deviceProperties.limits.subTexelPrecisionBits;
|
||||
score += deviceProperties.limits.mipmapPrecisionBits;
|
||||
score += deviceProperties.limits.maxDrawIndexedIndexValue;
|
||||
score += deviceProperties.limits.maxDrawIndirectCount;
|
||||
score += deviceProperties.limits.maxSamplerLodBias;
|
||||
score += deviceProperties.limits.maxSamplerAnisotropy;
|
||||
score += deviceProperties.limits.maxViewports;
|
||||
score += deviceProperties.limits.viewportSubPixelBits;
|
||||
score += deviceProperties.limits.minMemoryMapAlignment;
|
||||
score += deviceProperties.limits.minTexelBufferOffsetAlignment;
|
||||
score += deviceProperties.limits.minUniformBufferOffsetAlignment;
|
||||
score += deviceProperties.limits.minStorageBufferOffsetAlignment;
|
||||
score += deviceProperties.limits.minTexelOffset;
|
||||
score += deviceProperties.limits.maxTexelOffset;
|
||||
score += deviceProperties.limits.minTexelGatherOffset;
|
||||
score += deviceProperties.limits.maxTexelGatherOffset;
|
||||
score += deviceProperties.limits.minInterpolationOffset;
|
||||
score += deviceProperties.limits.maxInterpolationOffset;
|
||||
score += deviceProperties.limits.subPixelInterpolationOffsetBits;
|
||||
score += deviceProperties.limits.maxFramebufferWidth;
|
||||
score += deviceProperties.limits.maxFramebufferHeight;
|
||||
score += deviceProperties.limits.maxFramebufferLayers;
|
||||
score += deviceProperties.limits.framebufferColorSampleCounts;
|
||||
score += deviceProperties.limits.framebufferDepthSampleCounts;
|
||||
score += deviceProperties.limits.framebufferStencilSampleCounts;
|
||||
score += deviceProperties.limits.framebufferNoAttachmentsSampleCounts;
|
||||
score += deviceProperties.limits.maxColorAttachments;
|
||||
score += deviceProperties.limits.sampledImageColorSampleCounts;
|
||||
score += deviceProperties.limits.sampledImageIntegerSampleCounts;
|
||||
score += deviceProperties.limits.sampledImageDepthSampleCounts;
|
||||
score += deviceProperties.limits.sampledImageStencilSampleCounts;
|
||||
score += deviceProperties.limits.storageImageSampleCounts;
|
||||
score += deviceProperties.limits.maxSampleMaskWords;
|
||||
score += deviceProperties.limits.timestampComputeAndGraphics;
|
||||
score += deviceProperties.limits.timestampPeriod;
|
||||
score += deviceProperties.limits.maxClipDistances;
|
||||
score += deviceProperties.limits.maxCullDistances;
|
||||
score += deviceProperties.limits.maxCombinedClipAndCullDistances;
|
||||
score += deviceProperties.limits.discreteQueuePriorities;
|
||||
score += deviceProperties.limits.pointSizeGranularity;
|
||||
score += deviceProperties.limits.lineWidthGranularity;
|
||||
score += deviceProperties.limits.strictLines;
|
||||
score += deviceProperties.limits.standardSampleLocations;
|
||||
score += deviceProperties.limits.optimalBufferCopyOffsetAlignment;
|
||||
score += deviceProperties.limits.optimalBufferCopyRowPitchAlignment;
|
||||
score += deviceProperties.limits.nonCoherentAtomSize;
|
||||
}
|
||||
// Application can't function without geometry shaders
|
||||
if ( !deviceFeatures.geometryShader ) return 0;
|
||||
//
|
||||
{
|
||||
const uf::stl::vector<const char*> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties( device, nullptr, &extensionCount, nullptr );
|
||||
uf::stl::vector<VkExtensionProperties> availableExtensions( extensionCount );
|
||||
vkEnumerateDeviceExtensionProperties( device, nullptr, &extensionCount, availableExtensions.data() );
|
||||
std::set<uf::stl::string> requiredExtensions( deviceExtensions.begin(), deviceExtensions.end() );
|
||||
|
||||
for ( const auto& extension : availableExtensions )
|
||||
requiredExtensions.erase( extension.extensionName );
|
||||
|
||||
if ( !requiredExtensions.empty() ) return 0;
|
||||
}
|
||||
//
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
uf::stl::vector<VkSurfaceFormatKHR> formats;
|
||||
uf::stl::vector<VkPresentModeKHR> presentModes;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR( device, this->surface, &capabilities );
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, this->surface, &formatCount, nullptr);
|
||||
if ( formatCount != 0 ) {
|
||||
formats.resize( formatCount );
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR( device, this->surface, &formatCount, formats.data() );
|
||||
}
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR( device, this->surface, &presentModeCount, nullptr );
|
||||
if ( presentModeCount != 0 ) {
|
||||
presentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR( device, this->surface, &presentModeCount, presentModes.data() );
|
||||
}
|
||||
if ( formats.empty() || presentModes.empty() ) return 0;
|
||||
}
|
||||
if ( settings::gpuID != -1 && deviceProperties.deviceID == settings::gpuID ) {
|
||||
score = std::numeric_limits<int>::max();
|
||||
}
|
||||
UF_MSG_VALIDATION("Device name: " << deviceProperties.deviceName << " (" << deviceProperties.deviceID << ") has a score of " << score);
|
||||
return score;
|
||||
}
|
||||
|
||||
VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel level, bool begin ){
|
||||
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( getCommandPool(QueueEnum::TRANSFER), level, 1 );
|
||||
return createCommandBuffer( level, QueueEnum::TRANSFER, begin );
|
||||
}
|
||||
VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel level, QueueEnum queue, bool begin ){
|
||||
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo( getCommandPool(queue), level, 1 );
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
VK_CHECK_RESULT( vkAllocateCommandBuffers( logicalDevice, &cmdBufAllocateInfo, &commandBuffer ) );
|
||||
@ -427,6 +437,9 @@ VkCommandBuffer ext::vulkan::Device::createCommandBuffer( VkCommandBufferLevel l
|
||||
}
|
||||
|
||||
void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, bool free ) {
|
||||
return flushCommandBuffer( commandBuffer, QueueEnum::TRANSFER, free );
|
||||
}
|
||||
void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, QueueEnum queue, bool free ) {
|
||||
if ( commandBuffer == VK_NULL_HANDLE ) return;
|
||||
|
||||
VK_CHECK_RESULT( vkEndCommandBuffer( commandBuffer ) );
|
||||
@ -439,18 +452,12 @@ void ext::vulkan::Device::flushCommandBuffer( VkCommandBuffer commandBuffer, boo
|
||||
VkFenceCreateInfo fenceInfo = ext::vulkan::initializers::fenceCreateInfo(VK_FLAGS_NONE);
|
||||
VkFence fence;
|
||||
VK_CHECK_RESULT(vkCreateFence(logicalDevice, &fenceInfo, nullptr, &fence));
|
||||
|
||||
// Submit to the queue
|
||||
VK_CHECK_RESULT(vkQueueSubmit( getQueue( QueueEnum::TRANSFER ), 1, &submitInfo, fence));
|
||||
// vkQueueSubmit(device.queues.transfer, 1, &submitInfo, fence);
|
||||
// Wait for the fence to signal that command buffer has finished executing
|
||||
VK_CHECK_RESULT(vkQueueSubmit( getQueue( queue ), 1, &submitInfo, fence));
|
||||
VK_CHECK_RESULT(vkWaitForFences(logicalDevice, 1, &fence, VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
|
||||
|
||||
vkDestroyFence(logicalDevice, fence, nullptr);
|
||||
|
||||
if ( free ) vkFreeCommandBuffers(logicalDevice, getCommandPool( QueueEnum::TRANSFER ), 1, &commandBuffer);
|
||||
if ( free ) vkFreeCommandBuffers(logicalDevice, getCommandPool( queue ), 1, &commandBuffer);
|
||||
}
|
||||
|
||||
#if 0
|
||||
VkResult ext::vulkan::Device::createBuffer( VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties, VkDeviceSize size, VkBuffer* buffer, VkDeviceMemory* memory, const void* data ) {
|
||||
// Create the buffer handle
|
||||
VkBufferCreateInfo bufferCreateInfo = ext::vulkan::initializers::bufferCreateInfo(usage, size);
|
||||
@ -488,7 +495,7 @@ VkResult ext::vulkan::Device::createBuffer( VkBufferUsageFlags usage, VkMemoryPr
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, *buffer, *memory, 0));
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
VkResult ext::vulkan::Device::createBuffer(
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags memoryProperties,
|
||||
@ -701,33 +708,48 @@ void ext::vulkan::Device::initialize() {
|
||||
window->createSurface( instance, surface );
|
||||
}
|
||||
// Create physical device
|
||||
|
||||
uint32_t deviceCount = 0;
|
||||
uf::stl::vector<VkPhysicalDevice> physicalDevices;
|
||||
uf::stl::vector<::DeviceInfo> deviceInfos; // defined outside if we want to "multi"-gpu
|
||||
{
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices( this->instance, &deviceCount, nullptr );
|
||||
if ( deviceCount == 0 ) UF_EXCEPTION("Vulkan error: failed to find GPUs with Vulkan support!");
|
||||
|
||||
uf::stl::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices( this->instance, &deviceCount, devices.data() );
|
||||
|
||||
int bestScore = 0;
|
||||
for ( const VkPhysicalDevice& device : devices ) {
|
||||
int score = rate( device );
|
||||
if ( score <= bestScore ) continue;
|
||||
bestScore = score;
|
||||
physicalDevice = device;
|
||||
}
|
||||
|
||||
/*
|
||||
// Use an ordered map to automatically sort candidates by increasing score
|
||||
std::multimap<int, VkPhysicalDevice> candidates;
|
||||
for ( const VkPhysicalDevice& device : devices ) {
|
||||
int score = rate( device );
|
||||
candidates.insert( std::make_pair(score, device) );
|
||||
deviceInfos.reserve(deviceCount);
|
||||
physicalDevices.resize(deviceCount);
|
||||
|
||||
vkEnumeratePhysicalDevices( this->instance, &deviceCount, physicalDevices.data() );
|
||||
|
||||
size_t bestDeviceIndex = 0;
|
||||
for ( size_t i = 0; i < deviceCount; ++i ) {
|
||||
auto& deviceInfo = deviceInfos.emplace_back( rate(*this, physicalDevices[i]) );
|
||||
UF_MSG_VALIDATION("[" << i << "] "
|
||||
"Found device: " << deviceInfo.properties.deviceName << " ("
|
||||
"score: " << deviceInfo.score << " | "
|
||||
"device ID: " << deviceInfo.properties.deviceID << " | "
|
||||
"vendor ID: " << deviceInfo.properties.vendorID << " | "
|
||||
"API version: " << deviceInfo.properties.apiVersion << " | "
|
||||
"driver version: " << deviceInfo.properties.driverVersion << ")"
|
||||
);
|
||||
if ( settings::experimental::enableMultiGPU && deviceInfos[bestDeviceIndex].properties.vendorID != deviceInfo.properties.vendorID ) settings::experimental::enableMultiGPU = false;
|
||||
if ( deviceInfos[bestDeviceIndex].score >= deviceInfo.score ) continue;
|
||||
bestDeviceIndex = i;
|
||||
}
|
||||
// Check if the best candidate is suitable at all
|
||||
if ( candidates.rbegin()->first <= 0 ) UF_EXCEPTION("Vulkan error: failed to find a suitable GPU!");
|
||||
this->physicalDevice = candidates.rbegin()->second;
|
||||
*/
|
||||
if ( 0 <= ext::vulkan::settings::gpuID && ext::vulkan::settings::gpuID < deviceCount ) {
|
||||
bestDeviceIndex = ext::vulkan::settings::gpuID;
|
||||
}
|
||||
auto& deviceInfo = deviceInfos[bestDeviceIndex];
|
||||
this->physicalDevice = deviceInfo.handle;
|
||||
|
||||
UF_MSG_VALIDATION("Using device #" << bestDeviceIndex << " ("
|
||||
"score: " << deviceInfo.score << " | "
|
||||
"device ID: " << deviceInfo.properties.deviceID << " | "
|
||||
"vendor ID: " << deviceInfo.properties.vendorID << " | "
|
||||
"API version: " << deviceInfo.properties.apiVersion << " | "
|
||||
"driver version: " << deviceInfo.properties.driverVersion << ")"
|
||||
);
|
||||
}
|
||||
// Update properties
|
||||
{
|
||||
@ -738,7 +760,6 @@ void ext::vulkan::Device::initialize() {
|
||||
// Memory properties are used regularly for creating all kinds of buffers
|
||||
vkGetPhysicalDeviceMemoryProperties( this->physicalDevice, &memoryProperties );
|
||||
}
|
||||
UF_MSG_VALIDATION("Using device " << properties.deviceName << " (" << properties.deviceID << ")");
|
||||
{
|
||||
properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
@ -771,7 +792,7 @@ void ext::vulkan::Device::initialize() {
|
||||
// Create logical device
|
||||
{
|
||||
bool useSwapChain = true;
|
||||
VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
|
||||
VkQueueFlags requestedQueueTypes = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; // | VK_QUEUE_TRANSFER_BIT;
|
||||
uf::stl::vector<uf::stl::string> requestedExtensions;
|
||||
requestedExtensions.insert( requestedExtensions.end(), ext::vulkan::settings::requestedDeviceExtensions.begin(), ext::vulkan::settings::requestedDeviceExtensions.end() );
|
||||
#if UF_USE_OPENVR
|
||||
@ -861,11 +882,19 @@ void ext::vulkan::Device::initialize() {
|
||||
|
||||
enableRequestedDeviceFeatures( *this );
|
||||
|
||||
|
||||
|
||||
VkDeviceCreateInfo deviceCreateInfo = {};
|
||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
|
||||
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
|
||||
// deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
|
||||
deviceCreateInfo.pEnabledFeatures = nullptr;
|
||||
|
||||
VkDeviceGroupDeviceCreateInfo groupDeviceCreateInfo = {};
|
||||
groupDeviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO;
|
||||
groupDeviceCreateInfo.physicalDeviceCount = physicalDevices.size();
|
||||
groupDeviceCreateInfo.pPhysicalDevices = physicalDevices.data();
|
||||
|
||||
if ( deviceExtensions.size() > 0 ) {
|
||||
deviceCreateInfo.enabledExtensionCount = (uint32_t) deviceExtensions.size();
|
||||
@ -876,14 +905,13 @@ void ext::vulkan::Device::initialize() {
|
||||
VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures{};
|
||||
VkPhysicalDeviceShaderDrawParametersFeatures shaderDrawParametersFeatures{};
|
||||
VkPhysicalDeviceRobustness2FeaturesEXT robustnessFeatures{};
|
||||
{
|
||||
deviceCreateInfo.pEnabledFeatures = nullptr;
|
||||
deviceCreateInfo.pNext = &physicalDeviceFeatures2;
|
||||
}
|
||||
VkPhysicalDeviceBufferDeviceAddressFeatures bufferDeviceAddresFeatures{};
|
||||
VkPhysicalDeviceRayTracingPipelineFeaturesKHR rayTracingPipelineFeatures{};
|
||||
VkPhysicalDeviceAccelerationStructureFeaturesKHR accelerationStructureFeatures{};
|
||||
|
||||
{
|
||||
physicalDeviceFeatures2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
physicalDeviceFeatures2.features = enabledFeatures;
|
||||
physicalDeviceFeatures2.pNext = &descriptorIndexingFeatures;
|
||||
}
|
||||
{
|
||||
descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
|
||||
@ -891,21 +919,43 @@ void ext::vulkan::Device::initialize() {
|
||||
descriptorIndexingFeatures.shaderStorageImageArrayNonUniformIndexing = VK_TRUE;
|
||||
descriptorIndexingFeatures.runtimeDescriptorArray = VK_TRUE;
|
||||
descriptorIndexingFeatures.descriptorBindingVariableDescriptorCount = VK_TRUE;
|
||||
descriptorIndexingFeatures.pNext = &shaderDrawParametersFeatures;
|
||||
}
|
||||
{
|
||||
shaderDrawParametersFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETERS_FEATURES;
|
||||
shaderDrawParametersFeatures.shaderDrawParameters = VK_TRUE;
|
||||
shaderDrawParametersFeatures.pNext = &robustnessFeatures;
|
||||
}
|
||||
{
|
||||
robustnessFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
|
||||
robustnessFeatures.nullDescriptor = VK_TRUE;
|
||||
}
|
||||
|
||||
if ( vkCreateDevice( this->physicalDevice, &deviceCreateInfo, nullptr, &this->logicalDevice) != VK_SUCCESS ) {
|
||||
UF_EXCEPTION("Vulkan error: failed to create logical device!");
|
||||
{
|
||||
bufferDeviceAddresFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES;
|
||||
bufferDeviceAddresFeatures.bufferDeviceAddress = VK_TRUE;
|
||||
}
|
||||
{
|
||||
rayTracingPipelineFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_FEATURES_KHR;
|
||||
rayTracingPipelineFeatures.rayTracingPipeline = VK_TRUE;
|
||||
}
|
||||
{
|
||||
accelerationStructureFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_FEATURES_KHR;
|
||||
accelerationStructureFeatures.accelerationStructure = VK_TRUE;
|
||||
}
|
||||
|
||||
deviceCreateInfo.pNext = &physicalDeviceFeatures2;
|
||||
physicalDeviceFeatures2.pNext = &descriptorIndexingFeatures;
|
||||
descriptorIndexingFeatures.pNext = &shaderDrawParametersFeatures;
|
||||
shaderDrawParametersFeatures.pNext = &robustnessFeatures;
|
||||
robustnessFeatures.pNext = &bufferDeviceAddresFeatures;
|
||||
bufferDeviceAddresFeatures.pNext = &rayTracingPipelineFeatures;
|
||||
rayTracingPipelineFeatures.pNext = &accelerationStructureFeatures;
|
||||
|
||||
if ( settings::experimental::enableMultiGPU ) {
|
||||
UF_MSG_DEBUG("Multiple devices supported, using " << groupDeviceCreateInfo.physicalDeviceCount << " devices...");
|
||||
accelerationStructureFeatures.pNext = &groupDeviceCreateInfo;
|
||||
}
|
||||
|
||||
if ( vkCreateDevice( this->physicalDevice, &deviceCreateInfo, nullptr, &this->logicalDevice) != VK_SUCCESS ) UF_EXCEPTION("Vulkan error: failed to create logical device!");
|
||||
|
||||
{
|
||||
ext::json::Value payload = ext::json::array();
|
||||
for ( auto* c_str : deviceExtensions ) payload.emplace_back( uf::stl::string(c_str) );
|
||||
@ -949,17 +999,16 @@ void ext::vulkan::Device::initialize() {
|
||||
i++;
|
||||
}
|
||||
|
||||
UF_MSG_VALIDATION("Graphics queue: " << device.queueFamilyIndices.graphics);
|
||||
UF_MSG_VALIDATION("Compute queue: " << device.queueFamilyIndices.compute);
|
||||
UF_MSG_VALIDATION("Transfer queue: " << device.queueFamilyIndices.transfer);
|
||||
UF_MSG_VALIDATION("Present queue: " << device.queueFamilyIndices.present);
|
||||
|
||||
device.queueFamilyIndices.present = presentQueueNodeIndex;
|
||||
getQueue( QueueEnum::GRAPHICS );
|
||||
getQueue( QueueEnum::PRESENT );
|
||||
getQueue( QueueEnum::COMPUTE );
|
||||
getQueue( QueueEnum::TRANSFER );
|
||||
/*
|
||||
vkGetDeviceQueue( device, device.queueFamilyIndices.graphics, 0, &queues.graphics[std::this_thread::get_id()] );
|
||||
vkGetDeviceQueue( device, device.queueFamilyIndices.present, 0, &queues.present[std::this_thread::get_id()] );
|
||||
vkGetDeviceQueue( device, device.queueFamilyIndices.compute, 0, &queues.compute[std::this_thread::get_id()] );
|
||||
vkGetDeviceQueue( device, device.queueFamilyIndices.transfer, 0, &queues.transfer[std::this_thread::get_id()] );
|
||||
*/
|
||||
}
|
||||
// Set formats
|
||||
{
|
||||
@ -1069,10 +1118,24 @@ void ext::vulkan::Device::initialize() {
|
||||
allocatorInfo.physicalDevice = physicalDevice;
|
||||
allocatorInfo.instance = instance;
|
||||
allocatorInfo.device = logicalDevice;
|
||||
allocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
|
||||
allocatorInfo.pVulkanFunctions = &vulkanFunctions;
|
||||
|
||||
vmaCreateAllocator(&allocatorInfo, &allocator);
|
||||
}
|
||||
|
||||
{
|
||||
vkGetBufferDeviceAddressKHR = reinterpret_cast<PFN_vkGetBufferDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
|
||||
vkCmdBuildAccelerationStructuresKHR = reinterpret_cast<PFN_vkCmdBuildAccelerationStructuresKHR>(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR"));
|
||||
vkBuildAccelerationStructuresKHR = reinterpret_cast<PFN_vkBuildAccelerationStructuresKHR>(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR"));
|
||||
vkCreateAccelerationStructureKHR = reinterpret_cast<PFN_vkCreateAccelerationStructureKHR>(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR"));
|
||||
vkDestroyAccelerationStructureKHR = reinterpret_cast<PFN_vkDestroyAccelerationStructureKHR>(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR"));
|
||||
vkGetAccelerationStructureBuildSizesKHR = reinterpret_cast<PFN_vkGetAccelerationStructureBuildSizesKHR>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR"));
|
||||
vkGetAccelerationStructureDeviceAddressKHR = reinterpret_cast<PFN_vkGetAccelerationStructureDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR"));
|
||||
vkCmdTraceRaysKHR = reinterpret_cast<PFN_vkCmdTraceRaysKHR>(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR"));
|
||||
vkGetRayTracingShaderGroupHandlesKHR = reinterpret_cast<PFN_vkGetRayTracingShaderGroupHandlesKHR>(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR"));
|
||||
vkCreateRayTracingPipelinesKHR = reinterpret_cast<PFN_vkCreateRayTracingPipelinesKHR>(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR"));
|
||||
}
|
||||
}
|
||||
|
||||
void ext::vulkan::Device::destroy() {
|
||||
|
||||
@ -32,9 +32,6 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
|
||||
assert( shaders.size() > 0 );
|
||||
|
||||
uint32_t subpass = descriptor.subpass;
|
||||
|
||||
RenderMode& renderMode = ext::vulkan::getRenderMode( descriptor.renderMode, true );
|
||||
auto& renderTarget = renderMode.getRenderTarget( descriptor.renderTarget );
|
||||
|
||||
uf::stl::vector<VkDescriptorSetLayoutBinding> descriptorSetLayoutBindings;
|
||||
uf::stl::vector<VkPushConstantRange> pushConstantRanges;
|
||||
@ -103,6 +100,87 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
|
||||
pPipelineLayoutCreateInfo.pPushConstantRanges = pushConstantRanges.data();
|
||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pPipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
}
|
||||
// raytrace
|
||||
{
|
||||
uf::stl::vector<VkRayTracingShaderGroupCreateInfoKHR> shaderGroups;
|
||||
for ( auto* shader : shaders ) {
|
||||
if ( shader->descriptor.stage != VK_SHADER_STAGE_RAYGEN_BIT_KHR && shader->descriptor.stage != VK_SHADER_STAGE_MISS_BIT_KHR && shader->descriptor.stage != VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ) continue;
|
||||
|
||||
size_t shaderID = static_cast<uint32_t>(shaderDescriptors.size());
|
||||
bool isHit = shader->descriptor.stage & (VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_ANY_HIT_BIT_KHR | VK_SHADER_STAGE_INTERSECTION_BIT_KHR);
|
||||
|
||||
auto& shaderGroup = shaderGroups.emplace_back();
|
||||
shaderGroup.sType = VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_KHR;
|
||||
shaderGroup.type = !isHit ? VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_KHR : VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_KHR;
|
||||
shaderGroup.generalShader = !isHit ? shaderID : VK_SHADER_UNUSED_KHR;
|
||||
|
||||
shaderGroup.closestHitShader = (shader->descriptor.stage & VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) ? shaderID : VK_SHADER_UNUSED_KHR;
|
||||
shaderGroup.anyHitShader = (shader->descriptor.stage & VK_SHADER_STAGE_ANY_HIT_BIT_KHR) ? shaderID : VK_SHADER_UNUSED_KHR;
|
||||
shaderGroup.intersectionShader = (shader->descriptor.stage & VK_SHADER_STAGE_INTERSECTION_BIT_KHR) ? shaderID : VK_SHADER_UNUSED_KHR;
|
||||
|
||||
shaderDescriptors.emplace_back(shader->descriptor);
|
||||
}
|
||||
|
||||
if ( !shaderGroups.empty() ) {
|
||||
VkRayTracingPipelineCreateInfoKHR rayTracingPipelineCI{};
|
||||
rayTracingPipelineCI.sType = VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_KHR;
|
||||
rayTracingPipelineCI.stageCount = static_cast<uint32_t>(shaderDescriptors.size());
|
||||
rayTracingPipelineCI.pStages = shaderDescriptors.data();
|
||||
rayTracingPipelineCI.groupCount = static_cast<uint32_t>(shaderGroups.size());
|
||||
rayTracingPipelineCI.pGroups = shaderGroups.data();
|
||||
rayTracingPipelineCI.maxPipelineRayRecursionDepth = 1;
|
||||
rayTracingPipelineCI.layout = pipelineLayout;
|
||||
VK_CHECK_RESULT(vkCreateRayTracingPipelinesKHR(device, VK_NULL_HANDLE, VK_NULL_HANDLE, 1, &rayTracingPipelineCI, nullptr, &pipeline));
|
||||
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties{};
|
||||
rayTracingPipelineProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
|
||||
|
||||
VkPhysicalDeviceProperties2 deviceProperties2{};
|
||||
deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
deviceProperties2.pNext = &rayTracingPipelineProperties;
|
||||
|
||||
vkGetPhysicalDeviceProperties2(device.physicalDevice, &deviceProperties2);
|
||||
|
||||
const uint32_t handleSize = rayTracingPipelineProperties.shaderGroupHandleSize;
|
||||
const uint32_t handleSizeAligned = ALIGNED_SIZE(rayTracingPipelineProperties.shaderGroupHandleSize, rayTracingPipelineProperties.shaderGroupHandleAlignment);
|
||||
const uint32_t groupCount = static_cast<uint32_t>(shaderGroups.size());
|
||||
const uint32_t sbtSize = groupCount * handleSizeAligned;
|
||||
const VkBufferUsageFlags bufferUsageFlags = VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT;
|
||||
|
||||
std::vector<uint8_t> shaderHandleStorage(sbtSize);
|
||||
VK_CHECK_RESULT(vkGetRayTracingShaderGroupHandlesKHR(device, pipeline, 0, groupCount, sbtSize, shaderHandleStorage.data()));
|
||||
|
||||
requestedAlignment = rayTracingPipelineProperties.shaderGroupBaseAlignment;
|
||||
size_t raygenBufferIndex = initializeBuffer((const void*) (shaderHandleStorage.data() + handleSizeAligned * 0), handleSize, bufferUsageFlags);
|
||||
size_t raymissBufferIndex = initializeBuffer((const void*) (shaderHandleStorage.data() + handleSizeAligned * 1), handleSize, bufferUsageFlags);
|
||||
size_t rayhitBufferIndex = initializeBuffer((const void*) (shaderHandleStorage.data() + handleSizeAligned * 2), handleSize, bufferUsageFlags);
|
||||
requestedAlignment = 0;
|
||||
|
||||
Buffer raygenBuffer; raygenBuffer.aliasBuffer( buffers[raygenBufferIndex] );
|
||||
Buffer raymissBuffer; raymissBuffer.aliasBuffer( buffers[raymissBufferIndex] );
|
||||
Buffer rayhitBuffer; rayhitBuffer.aliasBuffer( buffers[rayhitBufferIndex] );
|
||||
|
||||
auto& raygenShaderSbtEntry = sbtEntries.emplace_back();
|
||||
raygenShaderSbtEntry.deviceAddress = raygenBuffer.getAddress();
|
||||
raygenShaderSbtEntry.stride = handleSizeAligned;
|
||||
raygenShaderSbtEntry.size = handleSizeAligned;
|
||||
|
||||
auto& raymissShaderSbtEntry = sbtEntries.emplace_back();
|
||||
raymissShaderSbtEntry.deviceAddress = raymissBuffer.getAddress();
|
||||
raymissShaderSbtEntry.stride = handleSizeAligned;
|
||||
raymissShaderSbtEntry.size = handleSizeAligned;
|
||||
|
||||
auto& rayhitShaderSbtEntry = sbtEntries.emplace_back();
|
||||
rayhitShaderSbtEntry.deviceAddress = rayhitBuffer.getAddress();
|
||||
rayhitShaderSbtEntry.stride = handleSizeAligned;
|
||||
rayhitShaderSbtEntry.size = handleSizeAligned;
|
||||
|
||||
auto& raycallShaderSbtEntry = sbtEntries.emplace_back();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute
|
||||
for ( auto* shaderPointer : shaders ) {
|
||||
auto& shader = *shaderPointer;
|
||||
@ -120,6 +198,9 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
|
||||
}
|
||||
// Graphic
|
||||
{
|
||||
RenderMode& renderMode = ext::vulkan::getRenderMode( descriptor.renderMode, true );
|
||||
auto& renderTarget = renderMode.getRenderTarget( descriptor.renderTarget );
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = ext::vulkan::initializers::pipelineInputAssemblyStateCreateInfo(
|
||||
descriptor.topology,
|
||||
0,
|
||||
@ -280,7 +361,7 @@ void ext::vulkan::Pipeline::initialize( const Graphic& graphic, const GraphicDes
|
||||
|
||||
PIPELINE_INITIALIZATION_INVALID:
|
||||
VK_DEBUG_VALIDATION_MESSAGE("Pipeline initialization invalid, updating next tick...");
|
||||
uf::thread::queue( uf::thread::get("Main"), [&]{
|
||||
uf::thread::queue( uf::thread::get(uf::thread::mainThreadName), [&]{
|
||||
this->initialize( graphic, descriptor );
|
||||
});
|
||||
return;
|
||||
@ -293,9 +374,12 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
|
||||
auto shaders = getShaders( graphic.material.shaders );
|
||||
for ( auto* shader : shaders ) {
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) bindPoint = VK_PIPELINE_BIND_POINT_COMPUTE;
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_RAYGEN_BIT_KHR ) bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_MISS_BIT_KHR ) bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR ) bindPoint = VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR;
|
||||
#if 1
|
||||
if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) {
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT || shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT ) {
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT || shader->descriptor.stage == VK_SHADER_STAGE_COMPUTE_BIT || shader->descriptor.stage == VK_SHADER_STAGE_RAYGEN_BIT_KHR ) {
|
||||
struct PushConstant {
|
||||
uint32_t pass;
|
||||
uint32_t draw;
|
||||
@ -312,26 +396,6 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, size, data );
|
||||
}
|
||||
}
|
||||
/*
|
||||
size_t offset = 0;
|
||||
for ( auto& pushConstant : shader->pushConstants ) {
|
||||
if ( shader->metadata.definitions.pushConstants.count("PushConstant") > 0 ) {
|
||||
if ( shader->descriptor.stage == VK_SHADER_STAGE_VERTEX_BIT ) {
|
||||
struct PushConstant {
|
||||
uint32_t pass;
|
||||
uint32_t draw;
|
||||
} pushConstant = { pass, draw };
|
||||
( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, sizeof(pushConstant), &pushConstant );
|
||||
}
|
||||
} else {
|
||||
size_t len = pushConstant.data().len;
|
||||
void* pointer = pushConstant.data().data;
|
||||
if ( len > 0 && pointer ) {
|
||||
vkCmdPushConstants( commandBuffer, pipelineLayout, shader->descriptor.stage, 0, len, pointer );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
// Bind descriptor sets describing shader binding points
|
||||
vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
@ -339,7 +403,19 @@ void ext::vulkan::Pipeline::record( const Graphic& graphic, const GraphicDescrip
|
||||
// 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, bindPoint, pipeline);
|
||||
|
||||
if ( bindPoint == VK_PIPELINE_BIND_POINT_COMPUTE && descriptor.inputs.dispatch.x != 0 && descriptor.inputs.dispatch.y != 0 && descriptor.inputs.dispatch.z != 0 ) {
|
||||
if ( bindPoint == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR ) {
|
||||
vkCmdTraceRaysKHR(
|
||||
commandBuffer,
|
||||
&sbtEntries[0],
|
||||
&sbtEntries[1],
|
||||
&sbtEntries[2],
|
||||
&sbtEntries[3],
|
||||
descriptor.inputs.width ? descriptor.inputs.width : ext::vulkan::settings::width,
|
||||
descriptor.inputs.height ? descriptor.inputs.height : ext::vulkan::settings::height,
|
||||
1
|
||||
);
|
||||
// UF_MSG_DEBUG("Target render mode: " << descriptor.renderMode << " | " << bindPoint << " " << pipeline << " " << pipelineLayout << " " << descriptorSet << " " << sbtEntries.size() << " " << descriptor.inputs.width << " " << descriptor.inputs.height );
|
||||
} else if ( bindPoint == VK_PIPELINE_BIND_POINT_COMPUTE && descriptor.inputs.dispatch.x != 0 && descriptor.inputs.dispatch.y != 0 && descriptor.inputs.dispatch.z != 0 ) {
|
||||
vkCmdDispatch(commandBuffer, descriptor.inputs.dispatch.x, descriptor.inputs.dispatch.y, descriptor.inputs.dispatch.z);
|
||||
}
|
||||
}
|
||||
@ -361,6 +437,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
struct Infos {
|
||||
uf::stl::vector<VkDescriptorBufferInfo> uniform;
|
||||
uf::stl::vector<VkDescriptorBufferInfo> storage;
|
||||
uf::stl::vector<VkDescriptorBufferInfo> accelerationStructure;
|
||||
|
||||
uf::stl::vector<VkDescriptorImageInfo> image;
|
||||
uf::stl::vector<VkDescriptorImageInfo> image2D;
|
||||
@ -382,16 +459,25 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
for ( auto& buffer : renderMode.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 & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) infos.accelerationStructure.emplace_back(buffer.descriptor);
|
||||
}
|
||||
// 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 & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) 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 & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) 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 & uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE ) infos.accelerationStructure.emplace_back(buffer.descriptor);
|
||||
}
|
||||
|
||||
if ( descriptor.subpass < renderTarget.passes.size() ) {
|
||||
@ -419,6 +505,23 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
infos.sampler.emplace_back(sampler.descriptor.info);
|
||||
}
|
||||
|
||||
//
|
||||
/*
|
||||
uf::stl::vector<VkWriteDescriptorSetAccelerationStructureKHR> accelerationStructureInfos;
|
||||
{
|
||||
auto& descriptorAccelerationStructureInfo = accelerationStructureInfos.emplace_back();
|
||||
descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
|
||||
descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
|
||||
descriptorAccelerationStructureInfo.pAccelerationStructures = &graphic.accelerationStructures.top.handle;
|
||||
}
|
||||
*/
|
||||
|
||||
VkWriteDescriptorSetAccelerationStructureKHR descriptorAccelerationStructureInfo{};
|
||||
descriptorAccelerationStructureInfo.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
|
||||
descriptorAccelerationStructureInfo.accelerationStructureCount = 1;
|
||||
descriptorAccelerationStructureInfo.pAccelerationStructures = &graphic.accelerationStructures.top.handle;
|
||||
|
||||
|
||||
// check if we can even consume that many infos
|
||||
size_t consumes = 0;
|
||||
for ( auto& layout : shader->descriptorSetLayoutBindings ) {
|
||||
@ -464,6 +567,7 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
|
||||
auto uniformBufferInfo = infos.uniform.begin();
|
||||
auto storageBufferInfo = infos.storage.begin();
|
||||
auto accelerationStructureInfo = infos.accelerationStructure.begin();
|
||||
|
||||
auto imageInfo = infos.image.begin();
|
||||
auto image2DInfo = infos.image2D.begin();
|
||||
@ -578,6 +682,19 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
));
|
||||
storageBufferInfo += layout.descriptorCount;
|
||||
} break;
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
|
||||
UF_ASSERT_BREAK_MSG( accelerationStructureInfo != infos.accelerationStructure.end(), "Filename: " << shader->filename << "\tCount: " << layout.descriptorCount )
|
||||
auto& writeDescriptorSet = writeDescriptorSets.emplace_back(ext::vulkan::initializers::writeDescriptorSet(
|
||||
descriptorSet,
|
||||
layout.descriptorType,
|
||||
layout.binding,
|
||||
&(*accelerationStructureInfo),
|
||||
layout.descriptorCount
|
||||
));
|
||||
writeDescriptorSet.pNext = &descriptorAccelerationStructureInfo;
|
||||
|
||||
accelerationStructureInfo += layout.descriptorCount;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -632,17 +749,17 @@ void ext::vulkan::Pipeline::update( const Graphic& graphic, const GraphicDescrip
|
||||
}
|
||||
|
||||
{
|
||||
// bool locked = renderMode.tryMutex();
|
||||
bool locked = renderMode.tryMutex();
|
||||
renderMode.rebuild = true;
|
||||
vkUpdateDescriptorSets( *device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL );
|
||||
// if ( locked ) renderMode.unlockMutex();
|
||||
if ( locked ) renderMode.unlockMutex();
|
||||
}
|
||||
return;
|
||||
|
||||
PIPELINE_UPDATE_INVALID:
|
||||
// graphic.process = false;
|
||||
VK_DEBUG_VALIDATION_MESSAGE("Pipeline update invalid, updating next tick...");
|
||||
uf::thread::queue( uf::thread::get("Main"), [&]{
|
||||
uf::thread::queue( uf::thread::get(uf::thread::mainThreadName), [&]{
|
||||
this->update( graphic, descriptor );
|
||||
});
|
||||
return;
|
||||
@ -667,7 +784,13 @@ void ext::vulkan::Pipeline::destroy() {
|
||||
descriptorSetLayout = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
if ( settings::experimental::dedicatedThread ) ext::vulkan::states::rebuild = true;
|
||||
// if ( settings::experimental::dedicatedThread ) ext::vulkan::states::rebuild = true;
|
||||
/*
|
||||
if ( ext::vulkan::hasRenderMode(descriptor.renderMode, true) ) {
|
||||
RenderMode& renderMode = ext::vulkan::getRenderMode(descriptor.renderMode, true);
|
||||
renderMode.rebuild = true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
uf::stl::vector<ext::vulkan::Shader*> ext::vulkan::Pipeline::getShaders( uf::stl::vector<ext::vulkan::Shader>& shaders ) {
|
||||
uf::stl::unordered_map<uf::stl::string, ext::vulkan::Shader*> map;
|
||||
@ -741,19 +864,19 @@ void ext::vulkan::Material::attachShader( const uf::stl::string& filename, VkSha
|
||||
uf::stl::string type = "unknown";
|
||||
switch ( stage ) {
|
||||
case VK_SHADER_STAGE_VERTEX_BIT: type = "vertex"; break;
|
||||
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: type = "tessellation_control"; break;
|
||||
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: type = "tessellation_evaluation"; break;
|
||||
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: type = "tessellation:control"; break;
|
||||
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: type = "tessellation:evaluation"; break;
|
||||
case VK_SHADER_STAGE_GEOMETRY_BIT: type = "geometry"; break;
|
||||
case VK_SHADER_STAGE_FRAGMENT_BIT: type = "fragment"; break;
|
||||
case VK_SHADER_STAGE_COMPUTE_BIT: type = "compute"; break;
|
||||
case VK_SHADER_STAGE_ALL_GRAPHICS: type = "all_graphics"; break;
|
||||
case VK_SHADER_STAGE_ALL_GRAPHICS: type = "all:graphics"; break;
|
||||
case VK_SHADER_STAGE_ALL: type = "all"; break;
|
||||
case VK_SHADER_STAGE_RAYGEN_BIT_KHR: type = "raygen"; break;
|
||||
case VK_SHADER_STAGE_ANY_HIT_BIT_KHR: type = "any_hit"; break;
|
||||
case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR: type = "closest_hit"; break;
|
||||
case VK_SHADER_STAGE_MISS_BIT_KHR: type = "miss"; break;
|
||||
case VK_SHADER_STAGE_INTERSECTION_BIT_KHR: type = "intersection"; break;
|
||||
case VK_SHADER_STAGE_CALLABLE_BIT_KHR: type = "callable"; break;
|
||||
case VK_SHADER_STAGE_RAYGEN_BIT_KHR: type = "ray:gen"; break;
|
||||
case VK_SHADER_STAGE_ANY_HIT_BIT_KHR: type = "ray:hit:any"; break;
|
||||
case VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR: type = "ray:hit:closest"; break;
|
||||
case VK_SHADER_STAGE_MISS_BIT_KHR: type = "ray:miss"; break;
|
||||
case VK_SHADER_STAGE_INTERSECTION_BIT_KHR: type = "ray:intersection"; break;
|
||||
case VK_SHADER_STAGE_CALLABLE_BIT_KHR: type = "ray:callable"; break;
|
||||
}
|
||||
shader.metadata.pipeline = pipeline;
|
||||
shader.metadata.type = type;
|
||||
@ -802,7 +925,7 @@ void ext::vulkan::Graphic::initializePipeline() {
|
||||
initializePipeline( this->descriptor, false );
|
||||
}
|
||||
ext::vulkan::Pipeline& ext::vulkan::Graphic::initializePipeline( const GraphicDescriptor& descriptor, bool update ) {
|
||||
auto& pipeline = pipelines[descriptor.hash()];
|
||||
auto& pipeline = pipelines[descriptor];
|
||||
|
||||
pipeline.initialize(*this, descriptor);
|
||||
pipeline.update(*this, descriptor);
|
||||
@ -836,15 +959,16 @@ void ext::vulkan::Graphic::initializeMesh( uf::Mesh& mesh, bool buffer ) {
|
||||
};
|
||||
uf::stl::vector<Queue> queue;
|
||||
descriptor.inputs.bufferOffset = buffers.empty() ? 0 : buffers.size() - 1;
|
||||
VkBufferUsageFlags baseUsage = VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR;
|
||||
|
||||
#define PARSE_ATTRIBUTE(i, usage) {\
|
||||
auto& buffer = mesh.buffers[i];\
|
||||
if ( queue.size() <= i ) queue.resize( i );\
|
||||
if ( !buffer.empty() ) queue.emplace_back(Queue{ (void*) buffer.data(), buffer.size(), usage });\
|
||||
if ( !buffer.empty() ) queue.emplace_back(Queue{ (void*) buffer.data(), buffer.size(), usage | baseUsage });\
|
||||
}
|
||||
#define PARSE_INPUT(name, usage){\
|
||||
if ( mesh.isInterleaved( mesh.name.interleaved ) ) PARSE_ATTRIBUTE(descriptor.inputs.name.interleaved, usage)\
|
||||
else for ( auto& attribute : descriptor.inputs.name.attributes ) PARSE_ATTRIBUTE(attribute.buffer, usage)\
|
||||
if ( mesh.isInterleaved( mesh.name.interleaved ) ) PARSE_ATTRIBUTE(descriptor.inputs.name.interleaved, usage | baseUsage)\
|
||||
else for ( auto& attribute : descriptor.inputs.name.attributes ) PARSE_ATTRIBUTE(attribute.buffer, usage | baseUsage)\
|
||||
}
|
||||
|
||||
PARSE_INPUT(vertex, uf::renderer::enums::Buffer::VERTEX)
|
||||
@ -914,7 +1038,7 @@ bool ext::vulkan::Graphic::updateMesh( uf::Mesh& mesh ) {
|
||||
return rebuild;
|
||||
}
|
||||
bool ext::vulkan::Graphic::hasPipeline( const GraphicDescriptor& descriptor ) const {
|
||||
return pipelines.count( descriptor.hash() ) > 0;
|
||||
return pipelines.count( descriptor ) > 0;
|
||||
}
|
||||
ext::vulkan::Pipeline& ext::vulkan::Graphic::getPipeline() {
|
||||
return getPipeline( descriptor );
|
||||
@ -924,11 +1048,11 @@ const ext::vulkan::Pipeline& ext::vulkan::Graphic::getPipeline() const {
|
||||
}
|
||||
ext::vulkan::Pipeline& ext::vulkan::Graphic::getPipeline( const GraphicDescriptor& descriptor ) {
|
||||
if ( !hasPipeline(descriptor) ) return initializePipeline( descriptor );
|
||||
return pipelines[descriptor.hash()];
|
||||
return pipelines[descriptor];
|
||||
}
|
||||
const ext::vulkan::Pipeline& ext::vulkan::Graphic::getPipeline( const GraphicDescriptor& descriptor ) const {
|
||||
if ( !hasPipeline(descriptor) ) UF_EXCEPTION("does not have pipeline");
|
||||
return pipelines.at(descriptor.hash());
|
||||
return pipelines.at(descriptor);
|
||||
}
|
||||
void ext::vulkan::Graphic::updatePipelines() {
|
||||
for ( auto pair : this->pipelines ) pair.second.update( *this );
|
||||
@ -939,13 +1063,13 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, size_t pass, s
|
||||
void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicDescriptor& descriptor, size_t pass, size_t draw ) const {
|
||||
if ( !process ) return;
|
||||
if ( !this->hasPipeline( descriptor ) ) {
|
||||
VK_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline");
|
||||
UF_MSG_ERROR(this << ": has no valid pipeline (" << descriptor.renderMode << " " << descriptor.renderTarget << ")");
|
||||
return;
|
||||
}
|
||||
|
||||
auto& pipeline = this->getPipeline( descriptor );
|
||||
if ( pipeline.descriptorSet == VK_NULL_HANDLE ) {
|
||||
VK_DEBUG_VALIDATION_MESSAGE(this << ": has no valid pipeline descriptor set");
|
||||
UF_MSG_ERROR(this << ": has no valid pipeline descriptor set (" << descriptor.renderMode << " " << descriptor.renderTarget << ")");
|
||||
return;
|
||||
}
|
||||
if ( !pipeline.metadata.process ) return;
|
||||
@ -984,26 +1108,6 @@ void ext::vulkan::Graphic::record( VkCommandBuffer commandBuffer, const GraphicD
|
||||
auto& attribute = descriptor.inputs.indirect.attributes.front();
|
||||
indirect.buffer = buffers.at((0 <= descriptor.inputs.indirect.interleaved ? descriptor.inputs.indirect.interleaved : attribute.buffer) + descriptor.inputs.bufferOffset).buffer;
|
||||
indirect.offset = 0 <= descriptor.inputs.indirect.interleaved ? descriptor.inputs.indirect.offset : attribute.offset;
|
||||
|
||||
/*
|
||||
.indices = indices.size(),
|
||||
.instances = 1,
|
||||
.indexID = mesh.index.count,
|
||||
.vertexID = mesh.vertex.count,
|
||||
|
||||
.instanceID = mesh.instance.count,
|
||||
.materialID = p.material,
|
||||
.objectID = 0,
|
||||
.vertices = vertices.size(),
|
||||
|
||||
if ( attribute.descriptor.pointer ) {
|
||||
pod::DrawCommand* drawCommands = (pod::DrawCommand*) attribute.descriptor.pointer;
|
||||
for ( auto i = 0; i < descriptor.inputs.indirect.count; ++i ) {
|
||||
auto& drawCommand = drawCommands[i];
|
||||
// UF_MSG_DEBUG( "DrawCommand[" << i << "]: " << drawCommand.indices << " " << drawCommand.instances << " " << drawCommand.indexID << " " << drawCommand.vertexID << " " << drawCommand.instanceID << " " << drawCommand.materialID << " " << drawCommand.objectID << " " << drawCommand.vertices );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
for ( auto& buffer : buffers ) {
|
||||
@ -1085,7 +1189,7 @@ void ext::vulkan::Graphic::destroy() {
|
||||
pipelines.clear();
|
||||
material.destroy();
|
||||
ext::vulkan::Buffers::destroy();
|
||||
ext::vulkan::states::rebuild = true;
|
||||
// ext::vulkan::states::rebuild = true;
|
||||
}
|
||||
|
||||
#include <uf/utils/string/hash.h>
|
||||
@ -1109,7 +1213,28 @@ void ext::vulkan::GraphicDescriptor::parse( ext::json::Value& metadata ) {
|
||||
}
|
||||
}
|
||||
ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() const {
|
||||
size_t hash{};
|
||||
size_t seed{};
|
||||
#if 0
|
||||
for ( auto i = 0; i < inputs.vertex.attributes.size(); ++i ) {
|
||||
uf::hash( inputs.vertex.attributes[i].descriptor.format );
|
||||
uf::hash( inputs.vertex.attributes[i].descriptor.offset );
|
||||
}
|
||||
for ( auto i = 0; i < inputs.index.attributes.size(); ++i ) {
|
||||
uf::hash( inputs.index.attributes[i].descriptor.format );
|
||||
uf::hash( inputs.index.attributes[i].descriptor.offset );
|
||||
}
|
||||
for ( auto i = 0; i < inputs.instance.attributes.size(); ++i ) {
|
||||
uf::hash( inputs.instance.attributes[i].descriptor.format );
|
||||
uf::hash( inputs.instance.attributes[i].descriptor.offset );
|
||||
}
|
||||
for ( auto i = 0; i < inputs.indirect.attributes.size(); ++i ) {
|
||||
uf::hash( inputs.indirect.attributes[i].descriptor.format );
|
||||
uf::hash( inputs.indirect.attributes[i].descriptor.offset );
|
||||
}
|
||||
#endif
|
||||
uf::hash( seed, subpass, renderMode, renderTarget, pipeline, topology, cullMode, fill, lineWidth, frontFace, depth.test, depth.write, depth.operation, depth.bias.enable, depth.bias.constant, depth.bias.slope, depth.bias.clamp );
|
||||
return seed;
|
||||
#if 0
|
||||
|
||||
hash += std::hash<decltype(subpass)>{}(subpass);
|
||||
if ( settings::invariant::individualPipelines )
|
||||
@ -1151,6 +1276,7 @@ ext::vulkan::GraphicDescriptor::hash_t ext::vulkan::GraphicDescriptor::hash() co
|
||||
hash += std::hash<decltype(depth.bias.clamp)>{}(depth.bias.clamp);
|
||||
|
||||
return hash;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -77,7 +77,7 @@ uf::Image ext::vulkan::RenderMode::screenshot( size_t attachmentID, size_t layer
|
||||
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocationCreateInfo, &temporary, &allocation, &allocationInfo));
|
||||
VkDeviceMemory temporaryMemory = allocationInfo.deviceMemory;
|
||||
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
|
||||
@ -162,7 +162,7 @@ uf::Image ext::vulkan::RenderMode::screenshot( size_t attachmentID, size_t layer
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
imageMemoryBarrier.newLayout = attachment.descriptor.layout;
|
||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
|
||||
device->flushCommandBuffer(copyCmd, true);
|
||||
device->flushCommandBuffer(copyCmd, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
const uint8_t* data;
|
||||
vmaMapMemory( allocator, allocation, (void**)&data );
|
||||
@ -177,6 +177,8 @@ ext::vulkan::GraphicDescriptor ext::vulkan::RenderMode::bindGraphicDescriptor( c
|
||||
// descriptor.renderMode = this->getName();
|
||||
descriptor.subpass = pass;
|
||||
descriptor.pipeline = metadata.pipeline;
|
||||
descriptor.inputs.width = this->width ? this->width : settings::width;
|
||||
descriptor.inputs.height = this->height ? this->height : settings::height;
|
||||
descriptor.parse( metadata.json["descriptor"] );
|
||||
return descriptor;
|
||||
}
|
||||
@ -224,7 +226,7 @@ void ext::vulkan::RenderMode::lockMutex( std::thread::id id ) {
|
||||
this->commands.lockMutex( id );
|
||||
}
|
||||
bool ext::vulkan::RenderMode::tryMutex( std::thread::id id ) {
|
||||
this->commands.tryMutex( id );
|
||||
return this->commands.tryMutex( id );
|
||||
}
|
||||
void ext::vulkan::RenderMode::unlockMutex( std::thread::id id ) {
|
||||
this->commands.unlockMutex( id );
|
||||
@ -232,6 +234,16 @@ void ext::vulkan::RenderMode::unlockMutex( std::thread::id id ) {
|
||||
std::lock_guard<std::mutex> ext::vulkan::RenderMode::guardMutex( std::thread::id id ) {
|
||||
return this->commands.guardMutex( id );
|
||||
}
|
||||
void ext::vulkan::RenderMode::cleanupCommands( std::thread::id id ) {
|
||||
auto& container = this->commands.container();
|
||||
for ( auto& pair : container ) {
|
||||
if ( pair.first == id ) continue;
|
||||
if ( pair.second.empty() ) continue;
|
||||
vkFreeCommandBuffers( *device, device->getCommandPool(this->getType() == "Compute" ? Device::QueueEnum::COMPUTE : Device::QueueEnum::GRAPHICS, pair.first), static_cast<uint32_t>(pair.second.size()), pair.second.data());
|
||||
pair.second.clear();
|
||||
}
|
||||
this->commands.cleanup( id );
|
||||
}
|
||||
void ext::vulkan::RenderMode::createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
|
||||
|
||||
}
|
||||
|
||||
@ -565,7 +565,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
for ( auto _ : layers ) {
|
||||
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
|
||||
auto& blitter = layer->blitter;
|
||||
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass ) continue;
|
||||
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass || blitter.accelerationStructures.top.handle ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(blitter.descriptor, currentSubpass);
|
||||
blitter.record(commands[i], descriptor);
|
||||
}
|
||||
@ -581,7 +581,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
|
||||
for ( auto _ : layers ) {
|
||||
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
|
||||
auto& blitter = layer->blitter;
|
||||
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass ) continue;
|
||||
if ( !blitter.initialized || !blitter.process || blitter.descriptor.subpass != currentPass || blitter.accelerationStructures.top.handle ) continue;
|
||||
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(blitter.descriptor, currentSubpass);
|
||||
blitter.record(commands[i], descriptor, eye, currentDraw++);
|
||||
}
|
||||
|
||||
522
engine/src/ext/vulkan/rendermodes/raytrace.cpp
Normal file
522
engine/src/ext/vulkan/rendermodes/raytrace.cpp
Normal file
@ -0,0 +1,522 @@
|
||||
#if UF_USE_VULKAN
|
||||
|
||||
#include <uf/ext/vulkan/vulkan.h>
|
||||
#include <uf/ext/vulkan/rendermodes/raytrace.h>
|
||||
#include <uf/ext/vulkan/initializers.h>
|
||||
#include <uf/utils/window/window.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/graphic/graphic.h>
|
||||
#include <uf/ext/vulkan/graphic.h>
|
||||
#include <uf/engine/graph/graph.h>
|
||||
#include <uf/utils/camera/camera.h>
|
||||
|
||||
namespace {
|
||||
//
|
||||
struct UniformDescriptor {
|
||||
struct Matrices {
|
||||
alignas(16) pod::Matrix4f view;
|
||||
alignas(16) pod::Matrix4f projection;
|
||||
alignas(16) pod::Matrix4f iView;
|
||||
alignas(16) pod::Matrix4f iProjection;
|
||||
alignas(16) pod::Matrix4f iProjectionView;
|
||||
alignas(16) pod::Vector4f eyePos;
|
||||
} matrices[2];
|
||||
};
|
||||
|
||||
void initializeGraphic( uf::renderer::RayTraceRenderMode& renderMode ) {
|
||||
auto& device = *renderMode.device;
|
||||
auto& blitter = *renderMode.getBlitter();
|
||||
|
||||
// setup buffers
|
||||
uf::Mesh mesh;
|
||||
mesh.bind<pod::Vertex_3F, uint16_t>();
|
||||
mesh.insertVertices<pod::Vertex_3F>({
|
||||
{ { -0.5f, -0.5f, 0.0f } },
|
||||
{ { 0.5f, -0.5f, 0.0f } },
|
||||
{ { 0.0f, 0.5f, 0.0f } },
|
||||
});
|
||||
mesh.insertIndices<uint16_t>({
|
||||
0, 1, 2
|
||||
});
|
||||
mesh.updateDescriptor();
|
||||
|
||||
blitter.initialize( renderMode.getName() );
|
||||
blitter.initializeMesh( mesh );
|
||||
blitter.process = false;
|
||||
|
||||
{
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
UniformDescriptor uniforms;
|
||||
for ( auto i = 0; i < 2; ++i ) {
|
||||
uniforms.matrices[i] = UniformDescriptor::Matrices{
|
||||
.view = camera.getView(i),
|
||||
.projection = camera.getProjection(i),
|
||||
.iView = uf::matrix::inverse( camera.getView(i) ),
|
||||
.iProjection = uf::matrix::inverse( camera.getProjection(i) ),
|
||||
.iProjectionView = uf::matrix::inverse( camera.getProjection(i) * camera.getView(i) ),
|
||||
.eyePos = camera.getEye( i ),
|
||||
};
|
||||
}
|
||||
blitter.initializeBuffer( (const void*) &uniforms, sizeof(UniformDescriptor), uf::renderer::enums::Buffer::UNIFORM );
|
||||
}
|
||||
|
||||
auto& image = blitter.material.textures.emplace_back();
|
||||
image.fromBuffers( NULL, 0, uf::renderer::enums::Format::R8G8B8A8_UNORM, uf::renderer::settings::width, uf::renderer::settings::height, 1, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
|
||||
pod::Matrix4f transformMatrix = uf::matrix::identity();
|
||||
auto vertexBufferIndex = blitter.initializeBuffer( (const void*) mesh.vertex.attributes.front().pointer, mesh.vertex.count * mesh.vertex.size, uf::renderer::enums::Buffer::ADDRESS | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR );
|
||||
auto indexBufferIndex = blitter.initializeBuffer( (const void*) mesh.index.attributes.front().pointer, mesh.index.count * mesh.index.size, uf::renderer::enums::Buffer::ADDRESS | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR );
|
||||
|
||||
blitter.requestedAlignment = 16;
|
||||
auto transformBufferIndex = blitter.initializeBuffer( &transformMatrix[0], sizeof(transformMatrix), uf::renderer::enums::Buffer::ADDRESS | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR );
|
||||
blitter.requestedAlignment = 0;
|
||||
|
||||
uf::renderer::Buffer vertexBuffer;
|
||||
uf::renderer::Buffer indexBuffer;
|
||||
uf::renderer::Buffer transformBuffer;
|
||||
uf::renderer::Buffer blasBuffer;
|
||||
uf::renderer::Buffer instancesBuffer;
|
||||
uf::renderer::Buffer tlasBuffer;
|
||||
uf::renderer::Buffer scratchBuffer;
|
||||
|
||||
// build SBT
|
||||
{
|
||||
uf::stl::string rayGenShaderFilename = uf::io::root+"/shaders/raytrace/shader.gen.spv";
|
||||
uf::stl::string rayMissShaderFilename = uf::io::root+"/shaders/raytrace/shader.miss.spv";
|
||||
uf::stl::string rayHitShaderFilename = uf::io::root+"/shaders/raytrace/shader.hit.spv";
|
||||
blitter.material.initializeShaders({
|
||||
{uf::io::resolveURI(rayGenShaderFilename), VK_SHADER_STAGE_RAYGEN_BIT_KHR},
|
||||
{uf::io::resolveURI(rayMissShaderFilename), VK_SHADER_STAGE_MISS_BIT_KHR},
|
||||
{uf::io::resolveURI(rayHitShaderFilename), VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR},
|
||||
});
|
||||
}
|
||||
|
||||
blitter.material.getShader("ray:gen").textures.emplace_back().aliasTexture( image );
|
||||
|
||||
VkPhysicalDeviceAccelerationStructurePropertiesKHR acclerationStructureProperties{};
|
||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rayTracingPipelineProperties{};
|
||||
VkPhysicalDeviceProperties2 deviceProperties2{};
|
||||
|
||||
{
|
||||
acclerationStructureProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ACCELERATION_STRUCTURE_PROPERTIES_KHR;
|
||||
|
||||
rayTracingPipelineProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PIPELINE_PROPERTIES_KHR;
|
||||
rayTracingPipelineProperties.pNext = &acclerationStructureProperties;
|
||||
|
||||
deviceProperties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||
deviceProperties2.pNext = &rayTracingPipelineProperties;
|
||||
|
||||
vkGetPhysicalDeviceProperties2(device.physicalDevice, &deviceProperties2);
|
||||
}
|
||||
|
||||
// build blas
|
||||
{
|
||||
// get address
|
||||
VkDeviceOrHostAddressConstKHR vertexBufferDeviceAddress{};
|
||||
VkDeviceOrHostAddressConstKHR indexBufferDeviceAddress{};
|
||||
VkDeviceOrHostAddressConstKHR transformBufferDeviceAddress{};
|
||||
|
||||
vertexBuffer.aliasBuffer( blitter.buffers[vertexBufferIndex] );
|
||||
indexBuffer.aliasBuffer( blitter.buffers[indexBufferIndex] );
|
||||
transformBuffer.aliasBuffer( blitter.buffers[transformBufferIndex] );
|
||||
|
||||
UF_ASSERT( vertexBuffer.buffer );
|
||||
UF_ASSERT( indexBuffer.buffer );
|
||||
UF_ASSERT( transformBuffer.buffer );
|
||||
|
||||
vertexBufferDeviceAddress.deviceAddress = vertexBuffer.getAddress();
|
||||
indexBufferDeviceAddress.deviceAddress = indexBuffer.getAddress();
|
||||
transformBufferDeviceAddress.deviceAddress = transformBuffer.getAddress();
|
||||
|
||||
// attribute info
|
||||
uf::Mesh::Attribute vertexAttribute;
|
||||
for ( auto& attribute : mesh.vertex.attributes ) if ( attribute.descriptor.name == "position" ) vertexAttribute = attribute;
|
||||
|
||||
UF_ASSERT( vertexAttribute.descriptor.name == "position" );
|
||||
|
||||
// blas info
|
||||
VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
|
||||
accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
|
||||
accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR;
|
||||
accelerationStructureGeometry.geometry.triangles.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR;
|
||||
|
||||
accelerationStructureGeometry.geometry.triangles.vertexFormat = vertexAttribute.descriptor.format;
|
||||
accelerationStructureGeometry.geometry.triangles.vertexData = vertexBufferDeviceAddress;
|
||||
accelerationStructureGeometry.geometry.triangles.maxVertex = mesh.vertex.count;
|
||||
accelerationStructureGeometry.geometry.triangles.vertexStride = vertexAttribute.stride;
|
||||
|
||||
accelerationStructureGeometry.geometry.triangles.indexType = VK_INDEX_TYPE_UINT16;
|
||||
accelerationStructureGeometry.geometry.triangles.indexData = indexBufferDeviceAddress;
|
||||
|
||||
accelerationStructureGeometry.geometry.triangles.transformData.deviceAddress = 0;
|
||||
accelerationStructureGeometry.geometry.triangles.transformData.hostAddress = nullptr;
|
||||
accelerationStructureGeometry.geometry.triangles.transformData = transformBufferDeviceAddress;
|
||||
|
||||
// size info
|
||||
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo{};
|
||||
accelerationStructureBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
accelerationStructureBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
accelerationStructureBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
accelerationStructureBuildGeometryInfo.geometryCount = 1;
|
||||
accelerationStructureBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||
|
||||
const uint32_t numTriangles = 1; // (mesh.index.count ? mesh.index.count : mesh.vertex.count) / 3;
|
||||
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo{};
|
||||
accelerationStructureBuildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
|
||||
|
||||
UF_MSG_DEBUG("vkGetAccelerationStructureBuildSizesKHR");
|
||||
uf::renderer::vkGetAccelerationStructureBuildSizesKHR(
|
||||
device,
|
||||
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
|
||||
&accelerationStructureBuildGeometryInfo,
|
||||
&numTriangles,
|
||||
&accelerationStructureBuildSizesInfo
|
||||
);
|
||||
|
||||
// build blas buffer
|
||||
size_t blasBufferIndex = blitter.initializeBuffer( NULL, accelerationStructureBuildSizesInfo.accelerationStructureSize, uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS );
|
||||
blitter.accelerationStructures.bottom.buffer.aliasBuffer( blitter.buffers[blasBufferIndex] );
|
||||
|
||||
// build blas handle
|
||||
VkAccelerationStructureCreateInfoKHR accelerationStructureCreateInfo{};
|
||||
accelerationStructureCreateInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
|
||||
accelerationStructureCreateInfo.buffer = blitter.accelerationStructures.bottom.buffer.buffer;
|
||||
accelerationStructureCreateInfo.size = accelerationStructureBuildSizesInfo.accelerationStructureSize;
|
||||
accelerationStructureCreateInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
|
||||
UF_MSG_DEBUG("vkCreateAccelerationStructureKHR");
|
||||
VK_CHECK_RESULT(uf::renderer::vkCreateAccelerationStructureKHR(device, &accelerationStructureCreateInfo, nullptr, &blitter.accelerationStructures.bottom.handle));
|
||||
|
||||
// build scratch buffer
|
||||
scratchBuffer.alignment = acclerationStructureProperties.minAccelerationStructureScratchOffsetAlignment;
|
||||
scratchBuffer.initialize( NULL, accelerationStructureBuildSizesInfo.buildScratchSize, uf::renderer::enums::Buffer::STORAGE | uf::renderer::enums::Buffer::ADDRESS );
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
|
||||
accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR;
|
||||
accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
||||
accelerationBuildGeometryInfo.dstAccelerationStructure = blitter.accelerationStructures.bottom.handle;
|
||||
accelerationBuildGeometryInfo.geometryCount = 1; // numTriangles;
|
||||
accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||
accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.getAddress();
|
||||
|
||||
VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{};
|
||||
accelerationStructureBuildRangeInfo.primitiveCount = numTriangles;
|
||||
accelerationStructureBuildRangeInfo.primitiveOffset = 0;
|
||||
accelerationStructureBuildRangeInfo.firstVertex = 0;
|
||||
accelerationStructureBuildRangeInfo.transformOffset = 0;
|
||||
std::vector<VkAccelerationStructureBuildRangeInfoKHR*> accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo };
|
||||
|
||||
// build blas
|
||||
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, uf::renderer::Device::QueueEnum::COMPUTE);
|
||||
|
||||
UF_MSG_DEBUG("vkCmdBuildAccelerationStructuresKHR");
|
||||
uf::renderer::vkCmdBuildAccelerationStructuresKHR(
|
||||
commandBuffer,
|
||||
1,
|
||||
&accelerationBuildGeometryInfo,
|
||||
accelerationBuildStructureRangeInfos.data()
|
||||
);
|
||||
device.flushCommandBuffer(commandBuffer, uf::renderer::Device::QueueEnum::COMPUTE);
|
||||
|
||||
VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
|
||||
accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
|
||||
accelerationDeviceAddressInfo.accelerationStructure = blitter.accelerationStructures.bottom.handle;
|
||||
blitter.accelerationStructures.bottom.deviceAddress = uf::renderer::vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
|
||||
|
||||
scratchBuffer.destroy();
|
||||
}
|
||||
// build tlas
|
||||
{
|
||||
// setup instances buffer
|
||||
VkAccelerationStructureInstanceKHR instance{};
|
||||
instance.transform = {
|
||||
1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f
|
||||
};
|
||||
instance.instanceCustomIndex = 0;
|
||||
instance.mask = 0xFF;
|
||||
instance.instanceShaderBindingTableRecordOffset = 0;
|
||||
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
|
||||
instance.accelerationStructureReference = blitter.accelerationStructures.bottom.deviceAddress;
|
||||
|
||||
auto instancesBufferIndex = blitter.initializeBuffer( NULL, sizeof(instance), uf::renderer::enums::Buffer::ADDRESS | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR );
|
||||
instancesBuffer.aliasBuffer( blitter.buffers[instancesBufferIndex] );
|
||||
blitter.updateBuffer( (const void*) &instance, sizeof(instance), instancesBuffer );
|
||||
|
||||
VkDeviceOrHostAddressConstKHR instanceDataDeviceAddress{};
|
||||
instanceDataDeviceAddress.deviceAddress = instancesBuffer.getAddress();
|
||||
|
||||
VkAccelerationStructureGeometryKHR accelerationStructureGeometry{};
|
||||
accelerationStructureGeometry.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR;
|
||||
accelerationStructureGeometry.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR;
|
||||
accelerationStructureGeometry.flags = VK_GEOMETRY_OPAQUE_BIT_KHR;
|
||||
accelerationStructureGeometry.geometry.instances.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR;
|
||||
accelerationStructureGeometry.geometry.instances.arrayOfPointers = VK_FALSE;
|
||||
accelerationStructureGeometry.geometry.instances.data = instanceDataDeviceAddress;
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR accelerationStructureBuildGeometryInfo{};
|
||||
accelerationStructureBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
accelerationStructureBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||
accelerationStructureBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
accelerationStructureBuildGeometryInfo.geometryCount = 1;
|
||||
accelerationStructureBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||
|
||||
const uint32_t primitive_count = 1;
|
||||
VkAccelerationStructureBuildSizesInfoKHR accelerationStructureBuildSizesInfo{};
|
||||
accelerationStructureBuildSizesInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR;
|
||||
UF_MSG_DEBUG("vkGetAccelerationStructureBuildSizesKHR");
|
||||
uf::renderer::vkGetAccelerationStructureBuildSizesKHR(
|
||||
device,
|
||||
VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR,
|
||||
&accelerationStructureBuildGeometryInfo,
|
||||
&primitive_count,
|
||||
&accelerationStructureBuildSizesInfo
|
||||
);
|
||||
|
||||
// build tlas buffer
|
||||
size_t tlasBufferIndex = blitter.initializeBuffer( NULL, accelerationStructureBuildSizesInfo.accelerationStructureSize, uf::renderer::enums::Buffer::ACCELERATION_STRUCTURE | uf::renderer::enums::Buffer::ADDRESS );
|
||||
blitter.accelerationStructures.top.buffer.aliasBuffer( blitter.buffers[tlasBufferIndex] );
|
||||
blitter.material.getShader("ray:gen").buffers.emplace_back().aliasBuffer( blitter.buffers[tlasBufferIndex] );
|
||||
|
||||
// build tlas handle
|
||||
VkAccelerationStructureCreateInfoKHR accelerationStructureCreateInfo{};
|
||||
accelerationStructureCreateInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR;
|
||||
accelerationStructureCreateInfo.buffer = blitter.accelerationStructures.top.buffer.buffer;
|
||||
accelerationStructureCreateInfo.size = accelerationStructureBuildSizesInfo.accelerationStructureSize;
|
||||
accelerationStructureCreateInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||
|
||||
UF_MSG_DEBUG("vkCreateAccelerationStructureKHR");
|
||||
VK_CHECK_RESULT(uf::renderer::vkCreateAccelerationStructureKHR(device, &accelerationStructureCreateInfo, nullptr, &blitter.accelerationStructures.top.handle));
|
||||
|
||||
// build scratch buffer
|
||||
scratchBuffer.alignment = acclerationStructureProperties.minAccelerationStructureScratchOffsetAlignment;
|
||||
scratchBuffer.initialize( NULL, accelerationStructureBuildSizesInfo.buildScratchSize, uf::renderer::enums::Buffer::STORAGE | uf::renderer::enums::Buffer::ADDRESS );
|
||||
UF_MSG_DEBUG(accelerationStructureBuildSizesInfo.buildScratchSize);
|
||||
|
||||
VkAccelerationStructureBuildGeometryInfoKHR accelerationBuildGeometryInfo{};
|
||||
accelerationBuildGeometryInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR;
|
||||
accelerationBuildGeometryInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR;
|
||||
accelerationBuildGeometryInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR;
|
||||
accelerationBuildGeometryInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR;
|
||||
accelerationBuildGeometryInfo.dstAccelerationStructure = blitter.accelerationStructures.top.handle;
|
||||
accelerationBuildGeometryInfo.geometryCount = 1;
|
||||
accelerationBuildGeometryInfo.pGeometries = &accelerationStructureGeometry;
|
||||
accelerationBuildGeometryInfo.scratchData.deviceAddress = scratchBuffer.getAddress();
|
||||
|
||||
VkAccelerationStructureBuildRangeInfoKHR accelerationStructureBuildRangeInfo{};
|
||||
accelerationStructureBuildRangeInfo.primitiveCount = 1;
|
||||
accelerationStructureBuildRangeInfo.primitiveOffset = 0;
|
||||
accelerationStructureBuildRangeInfo.firstVertex = 0;
|
||||
accelerationStructureBuildRangeInfo.transformOffset = 0;
|
||||
std::vector<VkAccelerationStructureBuildRangeInfoKHR*> accelerationBuildStructureRangeInfos = { &accelerationStructureBuildRangeInfo };
|
||||
|
||||
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, uf::renderer::Device::QueueEnum::COMPUTE);
|
||||
UF_MSG_DEBUG("vkCmdBuildAccelerationStructuresKHR");
|
||||
uf::renderer::vkCmdBuildAccelerationStructuresKHR(
|
||||
commandBuffer,
|
||||
1,
|
||||
&accelerationBuildGeometryInfo,
|
||||
accelerationBuildStructureRangeInfos.data()
|
||||
);
|
||||
device.flushCommandBuffer(commandBuffer, uf::renderer::Device::QueueEnum::COMPUTE);
|
||||
|
||||
VkAccelerationStructureDeviceAddressInfoKHR accelerationDeviceAddressInfo{};
|
||||
accelerationDeviceAddressInfo.sType = VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR;
|
||||
accelerationDeviceAddressInfo.accelerationStructure = blitter.accelerationStructures.top.handle;
|
||||
blitter.accelerationStructures.top.deviceAddress = uf::renderer::vkGetAccelerationStructureDeviceAddressKHR(device, &accelerationDeviceAddressInfo);
|
||||
|
||||
scratchBuffer.destroy();
|
||||
}
|
||||
blitter.descriptor.inputs.width = image.width;
|
||||
blitter.descriptor.inputs.height = image.height;
|
||||
|
||||
blitter.initializePipeline();
|
||||
|
||||
blitter.initialized = true;
|
||||
blitter.process = true;
|
||||
UF_MSG_DEBUG("Initialized ray tracer");
|
||||
}
|
||||
}
|
||||
|
||||
const uf::stl::string ext::vulkan::RayTraceRenderMode::getTarget() const {
|
||||
// auto& metadata = *const_cast<uf::Serializer*>(&this->metadata);
|
||||
// return metadata["target"].as<uf::stl::string>();
|
||||
return metadata.target;
|
||||
}
|
||||
void ext::vulkan::RayTraceRenderMode::setTarget( const uf::stl::string& target ) {
|
||||
// this->metadata["target"] = target;
|
||||
metadata.target = target;
|
||||
}
|
||||
|
||||
const uf::stl::string ext::vulkan::RayTraceRenderMode::getType() const {
|
||||
return "Compute";
|
||||
}
|
||||
const size_t ext::vulkan::RayTraceRenderMode::blitters() const {
|
||||
return 1;
|
||||
}
|
||||
ext::vulkan::Graphic* ext::vulkan::RayTraceRenderMode::getBlitter( size_t i ) {
|
||||
return &this->blitter;
|
||||
}
|
||||
uf::stl::vector<ext::vulkan::Graphic*> ext::vulkan::RayTraceRenderMode::getBlitters() {
|
||||
return { &this->blitter };
|
||||
}
|
||||
|
||||
ext::vulkan::GraphicDescriptor ext::vulkan::RayTraceRenderMode::bindGraphicDescriptor( const ext::vulkan::GraphicDescriptor& reference, size_t pass ) {
|
||||
ext::vulkan::GraphicDescriptor descriptor = ext::vulkan::RenderMode::bindGraphicDescriptor(reference, pass);
|
||||
descriptor.parse(metadata.json["descriptor"]);
|
||||
|
||||
// invalidate
|
||||
if ( metadata.target != "" && descriptor.renderMode != this->getName() && descriptor.renderMode != metadata.target ) {
|
||||
descriptor.invalidated = true;
|
||||
} else {
|
||||
descriptor.renderMode = this->getName();
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void ext::vulkan::RayTraceRenderMode::initialize( Device& device ) {
|
||||
ext::vulkan::RenderMode::initialize( device );
|
||||
|
||||
blitter.process = false;
|
||||
initializeGraphic(*this);
|
||||
}
|
||||
|
||||
void ext::vulkan::RayTraceRenderMode::tick() {
|
||||
ext::vulkan::RenderMode::tick();
|
||||
|
||||
bool resized = this->width == 0 && this->height == 0 && ext::vulkan::states::resized;
|
||||
bool rebuild = resized || ext::vulkan::states::rebuild || this->rebuild;
|
||||
|
||||
if ( resized ) {
|
||||
auto& image = blitter.material.textures.front();
|
||||
|
||||
image.destroy();
|
||||
image.fromBuffers( NULL, 0, uf::renderer::enums::Format::R8G8B8A8_UNORM, uf::renderer::settings::width, uf::renderer::settings::height, 1, 1, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT, VK_IMAGE_LAYOUT_GENERAL );
|
||||
|
||||
auto& shader = blitter.material.getShader("ray:gen");
|
||||
shader.textures.clear();
|
||||
shader.textures.emplace_back().aliasTexture( image );
|
||||
|
||||
blitter.descriptor.inputs.width = image.width;
|
||||
blitter.descriptor.inputs.height = image.height;
|
||||
|
||||
blitter.getPipeline().update( blitter );
|
||||
}
|
||||
|
||||
{
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& controller = scene.getController();
|
||||
auto& camera = controller.getComponent<uf::Camera>();
|
||||
|
||||
UniformDescriptor uniforms;
|
||||
for ( auto i = 0; i < 2; ++i ) {
|
||||
uniforms.matrices[i] = UniformDescriptor::Matrices{
|
||||
.view = camera.getView(i),
|
||||
.projection = camera.getProjection(i),
|
||||
.iView = uf::matrix::inverse( camera.getView(i) ),
|
||||
.iProjection = uf::matrix::inverse( camera.getProjection(i) ),
|
||||
.iProjectionView = uf::matrix::inverse( camera.getProjection(i) * camera.getView(i) ),
|
||||
.eyePos = camera.getEye( i ),
|
||||
};
|
||||
}
|
||||
|
||||
for ( auto& buffer : blitter.buffers ) {
|
||||
if ( !(buffer.usage & uf::renderer::enums::Buffer::UNIFORM) ) continue;
|
||||
if ( buffer.allocationInfo.size != sizeof(UniformDescriptor) ) continue;
|
||||
|
||||
buffer.update( (const void*) &uniforms, sizeof(UniformDescriptor) );
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( metadata.limiter.frequency > 0 ) {
|
||||
if ( metadata.limiter.timer > metadata.limiter.frequency ) {
|
||||
metadata.limiter.timer = 0;
|
||||
metadata.limiter.execute = true;
|
||||
} else {
|
||||
metadata.limiter.timer = metadata.limiter.timer + uf::physics::time::delta;
|
||||
metadata.limiter.execute = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if ( !graphic.initialized ) initializeGraphic(*this);
|
||||
}
|
||||
void ext::vulkan::RayTraceRenderMode::destroy() {
|
||||
auto& image = blitter.material.textures.front();
|
||||
image.screenshot().save("./data/rt.png");
|
||||
image.destroy();
|
||||
|
||||
blitter.destroy();
|
||||
|
||||
ext::vulkan::RenderMode::destroy();
|
||||
}
|
||||
|
||||
void ext::vulkan::RayTraceRenderMode::render() {
|
||||
if ( commandBufferCallbacks.count(EXECUTE_BEGIN) > 0 ) commandBufferCallbacks[EXECUTE_BEGIN]( VkCommandBuffer{} );
|
||||
|
||||
//lockMutex( this->mostRecentCommandPoolId );
|
||||
auto& commands = getCommands( this->mostRecentCommandPoolId );
|
||||
|
||||
// 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, UINT64_MAX ));
|
||||
VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] ));
|
||||
|
||||
VkSubmitInfo submitInfo = {};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.pWaitDstStageMask = NULL; // Pointer to the list of pipeline stages that the semaphore waits will occur at
|
||||
submitInfo.pWaitSemaphores = NULL; // Semaphore(s) to wait upon before the submitted command buffer starts executing
|
||||
submitInfo.waitSemaphoreCount = 0; // One wait semaphore
|
||||
submitInfo.pSignalSemaphores = NULL; // Semaphore(s) to be signaled when command buffers have completed
|
||||
submitInfo.signalSemaphoreCount = 0; // One signal semaphore
|
||||
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
|
||||
submitInfo.commandBufferCount = 1;
|
||||
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device->getQueue( uf::renderer::Device::QueueEnum::COMPUTE ), 1, &submitInfo, fences[states::currentBuffer]));
|
||||
|
||||
if ( commandBufferCallbacks.count(EXECUTE_END) > 0 ) commandBufferCallbacks[EXECUTE_END]( VkCommandBuffer{} );
|
||||
|
||||
this->executed = true;
|
||||
//unlockMutex( this->mostRecentCommandPoolId );
|
||||
}
|
||||
void ext::vulkan::RayTraceRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) {
|
||||
}
|
||||
void ext::vulkan::RayTraceRenderMode::createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
|
||||
// destroy if exists
|
||||
float width = this->width > 0 ? this->width : ext::vulkan::settings::width;
|
||||
float height = this->height > 0 ? this->height : ext::vulkan::settings::height;
|
||||
|
||||
VkCommandBufferBeginInfo cmdBufInfo = {};
|
||||
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
cmdBufInfo.pNext = nullptr;
|
||||
auto& commands = getCommands();
|
||||
for (size_t i = 0; i < commands.size(); ++i) {
|
||||
VK_CHECK_RESULT(vkBeginCommandBuffer(commands[i], &cmdBufInfo));
|
||||
|
||||
// pre-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_BEGIN) > 0 ) commandBufferCallbacks[CALLBACK_BEGIN]( commands[i] );
|
||||
|
||||
if ( blitter.process ) {
|
||||
auto& image = blitter.material.textures.front();
|
||||
auto descriptor = blitter.descriptor;
|
||||
descriptor.inputs.width = image.width;
|
||||
descriptor.inputs.height = image.height;
|
||||
blitter.getPipeline().record( blitter, descriptor, commands[i] );
|
||||
}
|
||||
|
||||
// post-renderpass commands
|
||||
if ( commandBufferCallbacks.count(CALLBACK_END) > 0 ) commandBufferCallbacks[CALLBACK_END]( commands[i] );
|
||||
|
||||
VK_CHECK_RESULT(vkEndCommandBuffer(commands[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -60,7 +60,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
|
||||
}
|
||||
}
|
||||
if ( !supported ) {
|
||||
VK_VALIDATION_MESSAGE("Transient attachment requested yet not supported, disabling...");
|
||||
// VK_VALIDATION_MESSAGE("Transient attachment requested yet not supported, disabling...");
|
||||
attachment->descriptor.usage &= ~VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,8 +166,7 @@ ext::vulkan::userdata_t ext::vulkan::jsonToUserdata( const ext::json::Value& pay
|
||||
auto get = input.as<int32_t>();
|
||||
memcpy( byteBuffer, &get, size );
|
||||
byteBuffer += size;
|
||||
}
|
||||
else if ( primitive == "uint32_t" ) {
|
||||
} else if ( primitive == "uint32_t" ) {
|
||||
size_t size = sizeof(uint32_t); // v["size"].as<size_t>();
|
||||
if ( byteBufferEnd < byteBuffer + size ) return false; // overflow
|
||||
auto get = input.as<int32_t>();
|
||||
@ -530,6 +529,22 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
binding
|
||||
};
|
||||
} break;
|
||||
case VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR: {
|
||||
// generate definition to JSON
|
||||
#if UF_SHADER_PARSE_AS_JSON
|
||||
{
|
||||
metadata.json["definitions"]["accelerationStructure"][name]["name"] = name;
|
||||
metadata.json["definitions"]["accelerationStructure"][name]["index"] = index;
|
||||
metadata.json["definitions"]["accelerationStructure"][name]["binding"] = binding;
|
||||
metadata.json["definitions"]["accelerationStructure"][name]["members"] = parseMembers(resource.type_id);
|
||||
}
|
||||
#endif
|
||||
metadata.definitions.accelerationStructure[name] = Shader::Metadata::Definition::AccelerationStructure{
|
||||
name,
|
||||
index,
|
||||
binding
|
||||
};
|
||||
} break;
|
||||
}
|
||||
descriptorSetLayoutBindings.push_back( ext::vulkan::initializers::descriptorSetLayoutBinding( descriptorType, stage, binding, arraySize ) );
|
||||
};
|
||||
@ -548,6 +563,7 @@ void ext::vulkan::Shader::initialize( ext::vulkan::Device& device, const uf::stl
|
||||
LOOP_RESOURCES( subpass_inputs, VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT );
|
||||
LOOP_RESOURCES( uniform_buffers, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER );
|
||||
LOOP_RESOURCES( storage_buffers, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER );
|
||||
LOOP_RESOURCES( acceleration_structures, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR );
|
||||
#undef LOOP_RESOURCES
|
||||
|
||||
{
|
||||
|
||||
@ -528,7 +528,7 @@ void ext::vulkan::Texture::fromBuffers(
|
||||
subresourceRange.levelCount = this->mips;
|
||||
subresourceRange.layerCount = this->layers;
|
||||
|
||||
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::GRAPHICS);
|
||||
setImageLayout(
|
||||
commandBuffer,
|
||||
image,
|
||||
@ -536,7 +536,7 @@ void ext::vulkan::Texture::fromBuffers(
|
||||
imageLayout,
|
||||
subresourceRange
|
||||
);
|
||||
device.flushCommandBuffer(commandBuffer);
|
||||
device.flushCommandBuffer(commandBuffer, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
this->imageLayout = imageLayout;
|
||||
}
|
||||
@ -575,7 +575,7 @@ void ext::vulkan::Texture::asRenderTarget( Device& device, uint32_t width, uint3
|
||||
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocInfo, &image, &allocation, &allocationInfo));
|
||||
deviceMemory = allocationInfo.deviceMemory;
|
||||
|
||||
VkCommandBuffer layoutCmd = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer layoutCmd = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
imageLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||
setImageLayout(
|
||||
@ -587,7 +587,7 @@ void ext::vulkan::Texture::asRenderTarget( Device& device, uint32_t width, uint3
|
||||
this->mips
|
||||
);
|
||||
|
||||
device.flushCommandBuffer(layoutCmd, true);
|
||||
device.flushCommandBuffer(layoutCmd, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
// Create sampler
|
||||
// sampler.initialize( device );
|
||||
@ -707,7 +707,7 @@ void ext::vulkan::Texture::update( void* data, VkDeviceSize bufferSize, VkImageL
|
||||
));
|
||||
|
||||
// Use a separate command buffer for texture loading
|
||||
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer commandBuffer = device.createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
// Image barrier for optimal image (target)
|
||||
// Optimal image will be used as destination for the copy
|
||||
@ -736,7 +736,7 @@ void ext::vulkan::Texture::update( void* data, VkDeviceSize bufferSize, VkImageL
|
||||
subresourceRange
|
||||
);
|
||||
|
||||
device.flushCommandBuffer(commandBuffer);
|
||||
device.flushCommandBuffer(commandBuffer, Device::QueueEnum::GRAPHICS);
|
||||
// Clean up staging resources
|
||||
staging.destroy();
|
||||
|
||||
@ -862,7 +862,7 @@ uf::Image ext::vulkan::Texture2D::screenshot( uint32_t layerID ) {
|
||||
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocationCreateInfo, &temporary, &allocation, &allocationInfo));
|
||||
VkDeviceMemory temporaryMemory = allocationInfo.deviceMemory;
|
||||
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
|
||||
@ -929,7 +929,7 @@ uf::Image ext::vulkan::Texture2D::screenshot( uint32_t layerID ) {
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
imageMemoryBarrier.newLayout = descriptor.imageLayout;
|
||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
|
||||
device->flushCommandBuffer(copyCmd, true);
|
||||
device->flushCommandBuffer(copyCmd, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
const uint8_t* data;
|
||||
vmaMapMemory( allocator, allocation, (void**)&data );
|
||||
@ -970,7 +970,7 @@ uf::Image ext::vulkan::Texture3D::screenshot( uint32_t layerID ) {
|
||||
VK_CHECK_RESULT(vmaCreateImage(allocator, &imageCreateInfo, &allocationCreateInfo, &temporary, &allocation, &allocationInfo));
|
||||
VkDeviceMemory temporaryMemory = allocationInfo.deviceMemory;
|
||||
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
|
||||
VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
|
||||
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
|
||||
@ -1042,7 +1042,7 @@ uf::Image ext::vulkan::Texture3D::screenshot( uint32_t layerID ) {
|
||||
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
|
||||
imageMemoryBarrier.newLayout = descriptor.imageLayout;
|
||||
vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_DEPENDENCY_BY_REGION_BIT, 0, NULL, 0, NULL, 1, &imageMemoryBarrier );
|
||||
device->flushCommandBuffer(copyCmd, true);
|
||||
device->flushCommandBuffer(copyCmd, Device::QueueEnum::GRAPHICS);
|
||||
|
||||
const uint8_t* data;
|
||||
vmaMapMemory( allocator, allocation, (void**)&data );
|
||||
|
||||
@ -14,7 +14,8 @@
|
||||
#include <atomic>
|
||||
|
||||
namespace {
|
||||
uf::stl::vector<VkFence> auxFences;
|
||||
uf::stl::vector<VkFence> auxFencesGraphics;
|
||||
uf::stl::vector<VkFence> auxFencesCompute;
|
||||
}
|
||||
|
||||
uint32_t ext::vulkan::settings::width = 1280;
|
||||
@ -36,6 +37,7 @@ VkFilter ext::vulkan::settings::swapchainUpscaleFilter = VK_FILTER_LINEAR;
|
||||
bool ext::vulkan::settings::experimental::dedicatedThread = false;
|
||||
bool ext::vulkan::settings::experimental::rebuildOnTickBegin = false;
|
||||
bool ext::vulkan::settings::experimental::batchQueueSubmissions = false;
|
||||
bool ext::vulkan::settings::experimental::enableMultiGPU = false;
|
||||
|
||||
// not so experimental
|
||||
bool ext::vulkan::settings::invariant::waitOnRenderEnd = false;
|
||||
@ -76,6 +78,17 @@ uf::stl::vector<ext::vulkan::RenderMode*> ext::vulkan::renderModes = {
|
||||
};
|
||||
uf::stl::unordered_map<uf::stl::string, ext::vulkan::RenderMode*> ext::vulkan::renderModesMap;
|
||||
|
||||
PFN_vkGetBufferDeviceAddressKHR ext::vulkan::vkGetBufferDeviceAddressKHR = NULL; // = reinterpret_cast<PFN_vkGetBufferDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetBufferDeviceAddressKHR"));
|
||||
PFN_vkCmdBuildAccelerationStructuresKHR ext::vulkan::vkCmdBuildAccelerationStructuresKHR = NULL; // = reinterpret_cast<PFN_vkCmdBuildAccelerationStructuresKHR>(vkGetDeviceProcAddr(device, "vkCmdBuildAccelerationStructuresKHR"));
|
||||
PFN_vkBuildAccelerationStructuresKHR ext::vulkan::vkBuildAccelerationStructuresKHR = NULL; // = reinterpret_cast<PFN_vkBuildAccelerationStructuresKHR>(vkGetDeviceProcAddr(device, "vkBuildAccelerationStructuresKHR"));
|
||||
PFN_vkCreateAccelerationStructureKHR ext::vulkan::vkCreateAccelerationStructureKHR = NULL; // = reinterpret_cast<PFN_vkCreateAccelerationStructureKHR>(vkGetDeviceProcAddr(device, "vkCreateAccelerationStructureKHR"));
|
||||
PFN_vkDestroyAccelerationStructureKHR ext::vulkan::vkDestroyAccelerationStructureKHR = NULL; // = reinterpret_cast<PFN_vkDestroyAccelerationStructureKHR>(vkGetDeviceProcAddr(device, "vkDestroyAccelerationStructureKHR"));
|
||||
PFN_vkGetAccelerationStructureBuildSizesKHR ext::vulkan::vkGetAccelerationStructureBuildSizesKHR = NULL; // = reinterpret_cast<PFN_vkGetAccelerationStructureBuildSizesKHR>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureBuildSizesKHR"));
|
||||
PFN_vkGetAccelerationStructureDeviceAddressKHR ext::vulkan::vkGetAccelerationStructureDeviceAddressKHR = NULL; // = reinterpret_cast<PFN_vkGetAccelerationStructureDeviceAddressKHR>(vkGetDeviceProcAddr(device, "vkGetAccelerationStructureDeviceAddressKHR"));
|
||||
PFN_vkCmdTraceRaysKHR ext::vulkan::vkCmdTraceRaysKHR = NULL; // = reinterpret_cast<PFN_vkCmdTraceRaysKHR>(vkGetDeviceProcAddr(device, "vkCmdTraceRaysKHR"));
|
||||
PFN_vkGetRayTracingShaderGroupHandlesKHR ext::vulkan::vkGetRayTracingShaderGroupHandlesKHR = NULL; // = reinterpret_cast<PFN_vkGetRayTracingShaderGroupHandlesKHR>(vkGetDeviceProcAddr(device, "vkGetRayTracingShaderGroupHandlesKHR"));
|
||||
PFN_vkCreateRayTracingPipelinesKHR ext::vulkan::vkCreateRayTracingPipelinesKHR = NULL; // = reinterpret_cast<PFN_vkCreateRayTracingPipelinesKHR>(vkGetDeviceProcAddr(device, "vkCreateRayTracingPipelinesKHR"));
|
||||
|
||||
VkResult ext::vulkan::CreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) {
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT");
|
||||
if ( func == nullptr ) return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
@ -297,13 +310,15 @@ void ext::vulkan::initialize() {
|
||||
}
|
||||
|
||||
{
|
||||
::auxFences.resize( swapchain.buffers );
|
||||
::auxFencesGraphics.resize( swapchain.buffers );
|
||||
::auxFencesCompute.resize( swapchain.buffers );
|
||||
|
||||
VkFenceCreateInfo fenceCreateInfo = {};
|
||||
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
for ( auto& fence : ::auxFences ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
|
||||
for ( auto& fence : ::auxFencesGraphics ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
|
||||
for ( auto& fence : ::auxFencesCompute ) VK_CHECK_RESULT(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence));
|
||||
}
|
||||
|
||||
uf::graph::initialize();
|
||||
@ -313,10 +328,10 @@ void ext::vulkan::initialize() {
|
||||
renderMode->initialize(device);
|
||||
}
|
||||
|
||||
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main");
|
||||
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
|
||||
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
|
||||
tasks.queue([&]{
|
||||
auto guard = renderMode->guardMutex();
|
||||
// auto guard = renderMode->guardMutex();
|
||||
// renderMode->lockMutex();
|
||||
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
|
||||
renderMode->createCommandBuffers();
|
||||
@ -336,7 +351,7 @@ void ext::vulkan::tick() {
|
||||
{
|
||||
auto& scene = uf::scene::getCurrentScene();
|
||||
auto& graph = scene.getGraph();
|
||||
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main");
|
||||
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread);
|
||||
for ( auto entity : graph ) {
|
||||
if ( !entity->hasComponent<uf::Graphic>() ) continue;
|
||||
ext::vulkan::Graphic& graphic = entity->getComponent<uf::Graphic>();
|
||||
@ -363,7 +378,7 @@ void ext::vulkan::tick() {
|
||||
#endif
|
||||
#if 0
|
||||
{
|
||||
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main");
|
||||
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread);
|
||||
for ( auto& renderMode : renderModes ) {
|
||||
if ( !renderMode ) continue;
|
||||
if ( !renderMode->device ) {
|
||||
@ -393,10 +408,10 @@ void ext::vulkan::tick() {
|
||||
}
|
||||
#endif
|
||||
{
|
||||
auto tasks = uf::thread::schedule(settings::experimental::dedicatedThread ? "Aux" : "Main");
|
||||
auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
|
||||
for ( auto& renderMode : renderModes ) { if ( !renderMode ) continue;
|
||||
if ( ext::vulkan::states::rebuild || renderMode->rebuild ) tasks.queue([&]{
|
||||
auto guard = renderMode->guardMutex();
|
||||
// auto guard = renderMode->guardMutex();
|
||||
// renderMode->lockMutex();
|
||||
if ( settings::invariant::individualPipelines ) renderMode->bindPipelines();
|
||||
renderMode->createCommandBuffers();
|
||||
@ -419,7 +434,7 @@ void ext::vulkan::render() {
|
||||
|
||||
for ( auto renderMode : renderModes ) {
|
||||
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue;
|
||||
renderMode->lockMutex( renderMode->mostRecentCommandPoolId );
|
||||
// renderMode->lockMutex( renderMode->mostRecentCommandPoolId );
|
||||
if ( renderMode->commandBufferCallbacks.count(RenderMode::EXECUTE_BEGIN) > 0 ) renderMode->commandBufferCallbacks[RenderMode::EXECUTE_BEGIN]( VkCommandBuffer{} );
|
||||
|
||||
if ( renderMode->getName() == "Gui" || renderMode->getName() == "" || renderMode->getName() == "Swapchain" )
|
||||
@ -431,7 +446,8 @@ void ext::vulkan::render() {
|
||||
// stuff we can batch
|
||||
{
|
||||
// Get next image in the swap chain (back/front buffer)
|
||||
uf::stl::vector<VkSubmitInfo> submits; submits.reserve( auxRenderModes.size() );
|
||||
uf::stl::vector<VkSubmitInfo> submitsGraphics; submitsGraphics.reserve( auxRenderModes.size() );
|
||||
uf::stl::vector<VkSubmitInfo> submitsCompute; submitsCompute.reserve( auxRenderModes.size() );
|
||||
for ( auto renderMode : auxRenderModes ) {
|
||||
auto submitInfo = renderMode->queue();
|
||||
if ( submitInfo.sType != VK_STRUCTURE_TYPE_SUBMIT_INFO ) continue;
|
||||
@ -440,15 +456,24 @@ void ext::vulkan::render() {
|
||||
uf::graph::render();
|
||||
uf::scene::render();
|
||||
|
||||
submits.emplace_back(submitInfo);
|
||||
if ( renderMode->getType() == "Compute" ) {
|
||||
submitsCompute.emplace_back(submitInfo);
|
||||
} else {
|
||||
submitsGraphics.emplace_back(submitInfo);
|
||||
}
|
||||
renderMode->executed = true;
|
||||
ext::vulkan::setCurrentRenderMode(NULL);
|
||||
}
|
||||
|
||||
if ( !submits.empty() ) {
|
||||
VK_CHECK_RESULT(vkWaitForFences(device, 1, &::auxFences[states::currentBuffer], VK_TRUE, UINT64_MAX));
|
||||
VK_CHECK_RESULT(vkResetFences(device, 1, &::auxFences[states::currentBuffer]));
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( Device::QueueEnum::GRAPHICS ), submits.size(), submits.data(), ::auxFences[states::currentBuffer]));
|
||||
if ( !submitsCompute.empty() ) {
|
||||
VK_CHECK_RESULT(vkWaitForFences(device, 1, &::auxFencesCompute[states::currentBuffer], VK_TRUE, UINT64_MAX));
|
||||
VK_CHECK_RESULT(vkResetFences(device, 1, &::auxFencesCompute[states::currentBuffer]));
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( Device::QueueEnum::COMPUTE ), submitsCompute.size(), submitsCompute.data(), ::auxFencesCompute[states::currentBuffer]));
|
||||
}
|
||||
if ( !submitsGraphics.empty() ) {
|
||||
VK_CHECK_RESULT(vkWaitForFences(device, 1, &::auxFencesGraphics[states::currentBuffer], VK_TRUE, UINT64_MAX));
|
||||
VK_CHECK_RESULT(vkResetFences(device, 1, &::auxFencesGraphics[states::currentBuffer]));
|
||||
VK_CHECK_RESULT(vkQueueSubmit(device.getQueue( Device::QueueEnum::GRAPHICS ), submitsGraphics.size(), submitsGraphics.data(), ::auxFencesGraphics[states::currentBuffer]));
|
||||
}
|
||||
}
|
||||
// stuff we can't batch
|
||||
@ -464,14 +489,15 @@ void ext::vulkan::render() {
|
||||
|
||||
for ( auto renderMode : renderModes ) {
|
||||
if ( renderMode->commandBufferCallbacks.count(RenderMode::EXECUTE_END) > 0 ) renderMode->commandBufferCallbacks[RenderMode::EXECUTE_END]( VkCommandBuffer{} );
|
||||
renderMode->unlockMutex( renderMode->mostRecentCommandPoolId );
|
||||
// renderMode->cleanupCommands( renderMode->mostRecentCommandPoolId );
|
||||
// renderMode->unlockMutex( renderMode->mostRecentCommandPoolId );
|
||||
}
|
||||
} else {
|
||||
for ( auto& renderMode : renderModes ) {
|
||||
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue;
|
||||
|
||||
// renderMode->lockMutex( renderMode->mostRecentCommandPoolId );
|
||||
auto guard = renderMode->guardMutex( renderMode->mostRecentCommandPoolId );
|
||||
// auto guard = renderMode->guardMutex( renderMode->mostRecentCommandPoolId );
|
||||
ext::vulkan::setCurrentRenderMode(renderMode);
|
||||
uf::graph::render();
|
||||
uf::scene::render();
|
||||
@ -479,6 +505,9 @@ void ext::vulkan::render() {
|
||||
ext::vulkan::setCurrentRenderMode(NULL);
|
||||
// renderMode->unlockMutex( renderMode->mostRecentCommandPoolId );
|
||||
}
|
||||
for ( auto& renderMode : renderModes ) {
|
||||
// renderMode->cleanupCommands( renderMode->mostRecentCommandPoolId );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -490,7 +519,8 @@ void ext::vulkan::destroy() {
|
||||
ext::vulkan::mutex.lock();
|
||||
synchronize();
|
||||
|
||||
for ( auto& fence : ::auxFences ) vkDestroyFence( device, fence, nullptr);
|
||||
for ( auto& fence : ::auxFencesGraphics ) vkDestroyFence( device, fence, nullptr);
|
||||
for ( auto& fence : ::auxFencesCompute ) vkDestroyFence( device, fence, nullptr);
|
||||
|
||||
Texture2D::empty.destroy();
|
||||
Texture3D::empty.destroy();
|
||||
|
||||
@ -164,9 +164,9 @@ size_t UF_API ext::xatlas::unwrapExperimental( pod::Graph& graph ) {
|
||||
|
||||
// pack
|
||||
#if UF_XATLAS_UNWRAP_MULTITHREAD
|
||||
auto tasks = uf::thread::schedule("Async");
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
#else
|
||||
auto tasks = uf::thread::schedule("Main");
|
||||
auto tasks = uf::thread::schedule(false);
|
||||
#endif
|
||||
for ( auto& pair : atlases ) {
|
||||
tasks.queue([&]{
|
||||
@ -518,9 +518,9 @@ size_t UF_API ext::xatlas::unwrapLazy( pod::Graph& graph ) {
|
||||
|
||||
// pack
|
||||
#if UF_XATLAS_UNWRAP_MULTITHREAD
|
||||
auto tasks = uf::thread::schedule("Async");
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
#else
|
||||
auto tasks = uf::thread::schedule("Main");
|
||||
auto tasks = uf::thread::schedule(false);
|
||||
#endif
|
||||
for ( auto& pair : atlases ) {
|
||||
tasks.queue([&]{
|
||||
|
||||
@ -52,11 +52,7 @@ namespace {
|
||||
for ( auto x : str.getString() ) addCh(x);
|
||||
}
|
||||
};
|
||||
#ifndef UF_USE_NCURSES
|
||||
bool uf::IoStream::ncurses = false;
|
||||
#else
|
||||
bool uf::IoStream::ncurses = true;
|
||||
#endif
|
||||
bool uf::IoStream::ncurses = false;
|
||||
uf::IoStream uf::iostream;
|
||||
|
||||
UF_API_CALL uf::IoStream::IoStream() {
|
||||
@ -66,58 +62,11 @@ uf::IoStream::~IoStream() {
|
||||
}
|
||||
|
||||
void UF_API_CALL uf::IoStream::initialize() {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !uf::IoStream::ncurses ) return;
|
||||
ext::ncurses.initialize();
|
||||
if ( ext::ncurses.hasColors() ) {
|
||||
ext::ncurses.startColor();
|
||||
|
||||
this->m_registeredColors = {
|
||||
{"Red", {1, COLOR_RED, COLOR_BLACK, "COLOR_RED" } },
|
||||
{"Green", {2, COLOR_GREEN, COLOR_BLACK, "COLOR_GREEN" } },
|
||||
{"Yellow", {3, COLOR_YELLOW, COLOR_BLACK, "COLOR_YELLOW" } },
|
||||
{"Blue", {4, COLOR_BLUE, COLOR_BLACK, "COLOR_BLUE" } },
|
||||
{"Cyan", {5, COLOR_CYAN, COLOR_BLACK, "COLOR_CYAN" } },
|
||||
{"Magenta", {6, COLOR_MAGENTA, COLOR_BLACK, "COLOR_MAGENTA" } },
|
||||
{"White", {7, COLOR_WHITE, COLOR_BLACK, "COLOR_WHITE" } },
|
||||
};
|
||||
for ( auto& pair : this->m_registeredColors ) {
|
||||
auto& color = pair.second;
|
||||
ext::ncurses.initPair( color.id, color.foreground, color.background );
|
||||
}
|
||||
this->setColor("White");
|
||||
} else {
|
||||
uf::iostream << "Color not supported!" << "\n";
|
||||
this->readChar();
|
||||
this->terminate();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void UF_API_CALL uf::IoStream::terminate() {
|
||||
#if UF_USE_NCURSES
|
||||
if (uf::IoStream::ncurses) ext::ncurses.terminate();
|
||||
#endif
|
||||
}
|
||||
void UF_API_CALL uf::IoStream::clear(bool all) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
#endif
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
if ( all ) {
|
||||
spec::terminal.clear();
|
||||
}
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
if ( all ) {
|
||||
ext::ncurses.move(0,0);
|
||||
ext::ncurses.clear(true);
|
||||
return;
|
||||
}
|
||||
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.move(::info.cursor.row, 0);
|
||||
ext::ncurses.clear();
|
||||
#endif
|
||||
spec::terminal.clear();
|
||||
}
|
||||
uf::stl::string uf::IoStream::getBuffer() {
|
||||
return ::info.output.buffer;
|
||||
@ -126,343 +75,51 @@ uf::stl::vector<uf::stl::string> uf::IoStream::getHistory() {
|
||||
return ::info.output.history;
|
||||
}
|
||||
void UF_API_CALL uf::IoStream::back() {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) return;
|
||||
if ( !uf::IoStream::ncurses ) return;
|
||||
/*
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
struct {
|
||||
int row = ::info.cursor.row, column = ::info.cursor.column;
|
||||
} target;
|
||||
if ( ::info.output.buffer.size() > 0 ) {
|
||||
::info.output.buffer = ::info.output.buffer.substr( 0, ::info.output.buffer.size() );
|
||||
} else if ( ::info.output.history.size() > 0 ) {
|
||||
::info.output.buffer = ::info.output.history.back();
|
||||
::info.output.history.erase( ::info.output.history.end() - 1 );
|
||||
ext::ncurses.move(::info.cursor.row, ::info.output.buffer.size(), ::info.cursor.row, ::info.cursor.column);
|
||||
}
|
||||
*/
|
||||
if ( !::info.output.buffer.empty() ) {
|
||||
::info.output.buffer.pop_back();
|
||||
ext::ncurses.delChar();
|
||||
} else if ( !::info.output.history.empty() ) {
|
||||
::info.output.buffer = ::info.output.history.back();
|
||||
::info.output.history.pop_back();
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.move(::info.cursor.row - 1, ::info.output.buffer.size(), ::info.cursor.row, ::info.cursor.column);
|
||||
}
|
||||
ext::ncurses.refresh();
|
||||
#endif
|
||||
}
|
||||
char UF_API_CALL uf::IoStream::readChar(const bool& loop) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
#endif
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
auto ch = std::cin.get();
|
||||
::info.input.history.push_back( std::to_string(ch) );
|
||||
return ch;
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
while ( loop ) {
|
||||
::info.character = ext::ncurses.getCh();
|
||||
if ( ::info.character == ERR ) continue;
|
||||
if ( ::info.character > 0 && ::info.character < 128 ) return ::info.character;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
auto ch = std::cin.get();
|
||||
|
||||
addCh(ch);
|
||||
// ::info.input.history.push_back( std::to_string(ch) );
|
||||
return ch;
|
||||
}
|
||||
uf::stl::string UF_API_CALL uf::IoStream::readString(const bool& loop) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
// static uf::stl::vector<uf::stl::string> history;
|
||||
#endif
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
uf::stl::string in;
|
||||
std::getline(std::cin, in);
|
||||
::info.input.history.push_back( in );
|
||||
return in;
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
/*uf::stl::string ::info.input.buffer;
|
||||
int ch;
|
||||
struct {
|
||||
int r = 0, c = 0;
|
||||
int r_max = 0, c_max = 0;
|
||||
} home;
|
||||
unsigned int cursor = 0;
|
||||
|
||||
uf::stl::string ::info.temporary;
|
||||
int ::info.indices.history = -1;*/
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.getMaxYX(::info.window.rows, ::info.window.columns);
|
||||
::info.origin = ::info.cursor;
|
||||
uf::stl::string str;
|
||||
std::getline(std::cin, str);
|
||||
|
||||
// break on new line or carriage return
|
||||
while ( loop && (::info.character = ext::ncurses.getCh()) != '\n' && ::info.character != '\r' ) {
|
||||
// err
|
||||
if ( ::info.character == ERR ) {
|
||||
continue;
|
||||
// mouse
|
||||
} else if ( ::info.character == KEY_MOUSE ) {
|
||||
/*
|
||||
MEVENT event;
|
||||
if ( wgetmouse(&event) == OK ) {
|
||||
|
||||
}
|
||||
*/
|
||||
// backspace
|
||||
} else if ( ::info.character == '\b' && ::info.input.buffer.length() > 0 ) {
|
||||
::info.input.buffer = ::info.input.buffer.substr( 0, ::info.input.buffer.length() - 1 );
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.move(::info.cursor.row, ::info.cursor.column-1, ::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.delChar();
|
||||
ext::ncurses.refresh();
|
||||
--::info.indices.buffer;
|
||||
// left/right arrow keys
|
||||
} else if ( ::info.character == KEY_LEFT || ::info.character == KEY_RIGHT ) {
|
||||
int dir = (::info.character == KEY_LEFT) ? -1 : 1;
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
if ( ::info.cursor.column < ::info.window.columns && ::info.cursor.column > ::info.origin.column ) {
|
||||
::info.cursor.column += dir;
|
||||
::info.indices.buffer += dir;
|
||||
ext::ncurses.move(-1, ::info.cursor.column);
|
||||
}
|
||||
// up/down arrow keys
|
||||
} else if ( ::info.character == KEY_UP || ::info.character == KEY_DOWN ) {
|
||||
if ( ::info.temporary == "" ) ::info.temporary = ::info.input.buffer;
|
||||
int dir = (::info.character == KEY_UP) ? -1 : 1;
|
||||
if ( ::info.indices.history - 1 >= 0 && ::info.indices.history + 1 < ::info.input.history.size() ) {
|
||||
ext::ncurses.move(::info.origin.row, ::info.origin.column, ::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.clear();
|
||||
::info.indices.history += dir;
|
||||
::info.input.buffer = *(::info.input.history.end() - ::info.indices.history - 1);
|
||||
::info.indices.buffer = ::info.input.buffer.size();
|
||||
uf::iostream << ::info.input.buffer;
|
||||
}
|
||||
/* else if ( delta < 0 ) {
|
||||
ext::ncurses.move(home.r, home.c);
|
||||
ext::ncurses.clear();
|
||||
::info.input.buffer = ::info.temporary;
|
||||
::info.indices.buffer = ::info.input.buffer.size();
|
||||
uf::iostream << ::info.input.buffer;
|
||||
}
|
||||
*/
|
||||
// valid characters
|
||||
} else if ( ::info.character >= 32 && ::info.character <= 127 ) {
|
||||
char at = ::info.character;
|
||||
::info.temporary = "";
|
||||
if ( ::info.indices.buffer == ::info.input.buffer.length() ) {
|
||||
::info.input.buffer += this->writeChar(at);
|
||||
} else {
|
||||
::info.input.buffer[::info.indices.buffer] = this->writeChar(at);
|
||||
}
|
||||
++::info.indices.buffer;
|
||||
}
|
||||
}
|
||||
uf::iostream << "\n";
|
||||
::info.input.history.push_back(::info.input.buffer);
|
||||
#endif
|
||||
return ::info.input.buffer;
|
||||
addStr(str);
|
||||
// ::info.input.history.push_back( str );
|
||||
return str;
|
||||
}
|
||||
uf::String UF_API_CALL uf::IoStream::readUString(const bool& loop) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
// static uf::stl::vector<uf::stl::string> history;
|
||||
#endif
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
uf::stl::string in;
|
||||
std::getline(std::cin, in);
|
||||
::info.input.history.push_back( in );
|
||||
return in;
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
/*uf::stl::string ::info.input.buffer;
|
||||
int ch;
|
||||
struct {
|
||||
int r = 0, c = 0;
|
||||
int r_max = 0, c_max = 0;
|
||||
} home;
|
||||
unsigned int cursor = 0;
|
||||
|
||||
uf::stl::string ::info.temporary;
|
||||
int ::info.indices.history = -1;*/
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.getMaxYX(::info.window.rows, ::info.window.columns);
|
||||
::info.origin = ::info.cursor;
|
||||
uf::stl::string str;
|
||||
std::getline(std::cin, str);
|
||||
|
||||
// break on new line or carriage return
|
||||
while ( loop && (::info.character = ext::ncurses.getCh()) != '\n' && ::info.character != '\r' ) {
|
||||
// err
|
||||
if ( ::info.character == ERR ) {
|
||||
continue;
|
||||
// mouse
|
||||
} else if ( ::info.character == KEY_MOUSE ) {
|
||||
/*
|
||||
MEVENT event;
|
||||
if ( wgetmouse(&event) == OK ) {
|
||||
|
||||
}
|
||||
*/
|
||||
// backspace
|
||||
} else if ( ::info.character == '\b' && ::info.input.buffer.length() > 0 ) {
|
||||
::info.input.buffer = ::info.input.buffer.substr( 0, ::info.input.buffer.length() - 1 );
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.move(::info.cursor.row, ::info.cursor.column-1, ::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.delChar();
|
||||
ext::ncurses.refresh();
|
||||
--::info.indices.buffer;
|
||||
// left/right arrow keys
|
||||
} else if ( ::info.character == KEY_LEFT || ::info.character == KEY_RIGHT ) {
|
||||
int dir = (::info.character == KEY_LEFT) ? -1 : 1;
|
||||
ext::ncurses.getYX(::info.cursor.row, ::info.cursor.column);
|
||||
if ( ::info.cursor.column < ::info.window.columns && ::info.cursor.column > ::info.origin.column ) {
|
||||
::info.cursor.column += dir;
|
||||
::info.indices.buffer += dir;
|
||||
ext::ncurses.move(-1, ::info.cursor.column);
|
||||
}
|
||||
// up/down arrow keys
|
||||
} else if ( ::info.character == KEY_UP || ::info.character == KEY_DOWN ) {
|
||||
if ( ::info.temporary == "" ) ::info.temporary = ::info.input.buffer;
|
||||
int dir = (::info.character == KEY_UP) ? -1 : 1;
|
||||
if ( ::info.indices.history - 1 >= 0 && ::info.indices.history + 1 < ::info.input.history.size() ) {
|
||||
ext::ncurses.move(::info.origin.row, ::info.origin.column, ::info.cursor.row, ::info.cursor.column);
|
||||
ext::ncurses.clear();
|
||||
::info.indices.history += dir;
|
||||
::info.input.buffer = *(::info.input.history.end() - ::info.indices.history - 1);
|
||||
::info.indices.buffer = ::info.input.buffer.size();
|
||||
uf::iostream << ::info.input.buffer;
|
||||
}
|
||||
/* else if ( delta < 0 ) {
|
||||
ext::ncurses.move(home.r, home.c);
|
||||
ext::ncurses.clear();
|
||||
::info.input.buffer = ::info.temporary;
|
||||
::info.indices.buffer = ::info.input.buffer.size();
|
||||
uf::iostream << ::info.input.buffer;
|
||||
}
|
||||
*/
|
||||
// valid characters
|
||||
// UTF-8 char
|
||||
} else {
|
||||
int iterations = 0;
|
||||
char at = ::info.character;
|
||||
if ( 32 <= ::info.character && ::info.character <= 127 ) iterations = 1;
|
||||
if ( 194 <= ::info.character && ::info.character <= 223 ) iterations = 2;
|
||||
if ( 224 <= ::info.character && ::info.character <= 239 ) iterations = 3;
|
||||
if ( 240 <= ::info.character && ::info.character <= 244 ) iterations = 4;
|
||||
for ( int i = 0; i < iterations; ++i, ++::info.indices.buffer ) {
|
||||
if ( at != ::info.character ) at = ext::ncurses.getCh();
|
||||
if ( ::info.indices.buffer == ::info.input.buffer.length() ) ::info.input.buffer += this->writeChar(at);
|
||||
else ::info.input.buffer[::info.indices.buffer] = this->writeChar(at);
|
||||
at = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
// ANSI / 1-byte UTF-8
|
||||
} else if ( 32 <= ch && ch <= 127 ) {
|
||||
char at = ch;
|
||||
if ( cursor == ::info.input.buffer.length() ) {
|
||||
::info.input.buffer += this->writeChar(at);
|
||||
} else {
|
||||
::info.input.buffer[cursor] = this->writeChar(at);
|
||||
}
|
||||
++cursor;
|
||||
// 2-byte UTF-8
|
||||
} else if ( 194 <= ch && ch <= 223 ) {
|
||||
char at = ch;
|
||||
for ( int i = 0; i < 2; ++i, ++cursor ) {
|
||||
if ( at != ch ) at = ext::ncurses.getCh();
|
||||
if ( cursor == ::info.input.buffer.length() ) ::info.input.buffer += this->writeChar(at);
|
||||
else ::info.input.buffer[cursor] = this->writeChar(at);
|
||||
at = 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
uf::iostream << "\n";
|
||||
::info.input.history.push_back(::info.input.buffer);
|
||||
#endif
|
||||
return ::info.input.buffer;
|
||||
addUStr(str);
|
||||
// ::info.input.history.push_back( str );
|
||||
return str;
|
||||
}
|
||||
char UF_API_CALL uf::IoStream::writeChar( char ch ) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
#endif
|
||||
addCh(ch);
|
||||
/*
|
||||
if ( ch == '\r' ) ch = '\n';
|
||||
if ( ch != '\n' ) {
|
||||
::info.output.buffer += ch;
|
||||
} else {
|
||||
this->writeString("new line: " + ::info.output.buffer + "\n");
|
||||
::info.output.history.push_back(::info.output.buffer);
|
||||
::info.output.buffer = "";
|
||||
}
|
||||
*/
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
if ( ch == '\n' ) std::cout << std::endl;
|
||||
else std::cout << ch;
|
||||
::info.input.history.push_back( std::to_string(ch) );
|
||||
return ch;
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
ext::ncurses.addChar(ch);
|
||||
ext::ncurses.refresh();
|
||||
#endif
|
||||
|
||||
if ( ch == '\n' ) std::cout << std::endl;
|
||||
else std::cout << ch;
|
||||
// ::info.input.history.push_back( std::to_string(ch) );
|
||||
return ch;
|
||||
}
|
||||
const uf::stl::string& UF_API_CALL uf::IoStream::writeString( const uf::stl::string& str ) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
#endif
|
||||
addStr(str);
|
||||
/*
|
||||
std::size_t needle;
|
||||
uf::stl::string haystack = str;
|
||||
while ( (needle = haystack.find('\n')) != uf::stl::string::npos ) {
|
||||
::info.output.buffer += haystack.substr( 0, needle );
|
||||
::info.output.history.push_back(::info.output.buffer);
|
||||
::info.output.buffer = "";
|
||||
haystack = haystack.substr( needle + 1 );
|
||||
}
|
||||
::info.output.buffer += haystack;
|
||||
*/
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
if ( str == "\n" ) std::cout << std::endl;
|
||||
else std::cout << str;
|
||||
::info.input.history.push_back( str );
|
||||
return str;
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
ext::ncurses.addStr(str.c_str());
|
||||
ext::ncurses.refresh();
|
||||
#endif
|
||||
|
||||
if ( str == "\n" ) std::cout << std::endl;
|
||||
else std::cout << str;
|
||||
// ::info.input.history.push_back( str );
|
||||
return str;
|
||||
}
|
||||
const uf::String& UF_API_CALL uf::IoStream::writeUString( const uf::String& str ) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
#endif
|
||||
addUStr(str);
|
||||
/*
|
||||
std::size_t needle;
|
||||
auto haystack = str.getString();
|
||||
while ( (needle = haystack.find('\n')) != uf::stl::string::npos ) {
|
||||
::info.output.buffer += uf::stl::string((const char*) haystack.substr( 0, needle ).c_str());
|
||||
::info.output.history.push_back(::info.output.buffer);
|
||||
::info.output.buffer = "";
|
||||
haystack = haystack.substr( needle + 1 );
|
||||
}
|
||||
*/
|
||||
if ( !uf::IoStream::ncurses ) {
|
||||
std::cout << (const char*) str.getString().c_str();
|
||||
::info.input.history.push_back( str );
|
||||
return str;
|
||||
}
|
||||
#if UF_USE_NCURSES
|
||||
ext::ncurses.addStr((const char*) str.getString().c_str());
|
||||
ext::ncurses.refresh();
|
||||
#endif
|
||||
|
||||
std::cout << (const char*) str.getString().c_str();
|
||||
// ::info.input.history.push_back( str );
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -669,19 +326,6 @@ uf::stl::string uf::IoStream::getColor() {
|
||||
return this->m_currentColor;
|
||||
}
|
||||
void UF_API_CALL uf::IoStream::setColor( const uf::stl::string& str ) {
|
||||
#if UF_USE_NCURSES
|
||||
if ( !uf::IoStream::ncurses ) return;
|
||||
if ( !ext::ncurses.initialized() ) this->initialize();
|
||||
|
||||
if ( this->m_registeredColors.count(str) < 1 ) return;
|
||||
|
||||
if ( ::info.color.last != 0 ) ext::ncurses.attrOff(COLOR_PAIR(::info.color.last));
|
||||
short id = this->m_registeredColors.at(str).id;
|
||||
ext::ncurses.attrOn(COLOR_PAIR(id));
|
||||
::info.color.last = id;
|
||||
|
||||
this->m_currentColor = str;
|
||||
#endif
|
||||
}
|
||||
|
||||
// manip via stream manipulator
|
||||
|
||||
@ -8,36 +8,45 @@ float uf::thread::limiter = 1.0f / 120.0f;
|
||||
uint uf::thread::workers = 1;
|
||||
std::thread::id uf::thread::mainThreadId = std::this_thread::get_id();
|
||||
bool uf::thread::async = false;
|
||||
uf::stl::string uf::thread::workerThreadName = "Worker";
|
||||
uf::stl::string uf::thread::mainThreadName = "Main";
|
||||
|
||||
#define UF_THREAD_ANNOUNCE(x) //UF_MSG_DEBUG(x)
|
||||
#define UF_THREAD_ANNOUNCE(x) UF_MSG_DEBUG(x)
|
||||
|
||||
void UF_API uf::thread::start( pod::Thread& thread ) { if ( thread.running ) return;
|
||||
thread.thread = std::thread( uf::thread::tick, std::ref(thread) );
|
||||
thread.running = true;
|
||||
}
|
||||
void UF_API uf::thread::quit( pod::Thread& thread ) { // if ( !thread.running ) return;
|
||||
void UF_API uf::thread::quit( pod::Thread& thread ) { if ( !thread.running ) return;
|
||||
thread.running = false;
|
||||
thread.conditions.queued.notify_one();
|
||||
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
bool locked = false;
|
||||
// if ( thread.mutex != NULL ) locked = thread.mutex->try_lock();
|
||||
if ( thread.thread.joinable() ) thread.thread.join();
|
||||
if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
// if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
|
||||
}
|
||||
void UF_API uf::thread::tick( pod::Thread& thread ) {
|
||||
#if !UF_ENV_DREAMCAST
|
||||
bool res = SetThreadAffinityMask(GetCurrentThread(), (1u << thread.affinity));
|
||||
if ( !res ) UF_THREAD_ANNOUNCE("Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on ID " << pthread_self() << "/" << thread.affinity << ")");
|
||||
if ( !res ) UF_THREAD_ANNOUNCE("Failed to set affinity of Thread #" << thread.uid << " (" << thread.name << " on core " << pthread_self() << "/" << thread.affinity << ")");
|
||||
#endif
|
||||
UF_THREAD_ANNOUNCE("Starting Thread #" << thread.uid << " (" << thread.name << " on ID " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)");
|
||||
UF_THREAD_ANNOUNCE("Starting Thread #" << thread.uid << " (" << thread.name << " on core " << thread.affinity << ")" << (thread.limiter ? " (Limiter: " + std::to_string(1.0f / thread.limiter) + " FPS)" : ""));
|
||||
thread.timer.start();
|
||||
|
||||
while ( thread.running ) {
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
thread.conditions.queued.wait(lock, [&]{
|
||||
return !thread.queue.empty() || !thread.running;
|
||||
});
|
||||
|
||||
uf::thread::process( thread );
|
||||
if ( thread.terminates && thread.queue.empty() && thread.container.empty() ) uf::thread::quit( thread );
|
||||
|
||||
if ( thread.limiter > 0 ) {
|
||||
long long sleep = (thread.limiter * 1000) - thread.timer.elapsed().asMilliseconds();
|
||||
if ( sleep > 0 ) {
|
||||
// UF_THREAD_ANNOUNCE("Thread #" << thread.uid << " (" << thread.name << " on core " << thread.affinity << ") will sleep for " << sleep << "ms");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
|
||||
}
|
||||
thread.timer.reset();
|
||||
@ -48,17 +57,15 @@ void UF_API uf::thread::tick( pod::Thread& thread ) {
|
||||
pod::Thread& UF_API uf::thread::fetchWorker( const uf::stl::string& name ) {
|
||||
static int current = 0;
|
||||
static int limit = uf::thread::workers;
|
||||
static uint threads = std::thread::hardware_concurrency();
|
||||
int tries = 8;
|
||||
while ( --tries >= 0 ) {
|
||||
if ( ++current >= limit ) current = 0;
|
||||
uf::stl::string thread = name;
|
||||
if ( current > 0 ) thread += " " + std::to_string(current);
|
||||
auto& pod = uf::thread::get(thread);
|
||||
if ( std::this_thread::get_id() != pod.thread.get_id() ) return pod;
|
||||
}
|
||||
|
||||
return uf::thread::get("Main");
|
||||
|
||||
uf::stl::string thread = name + " " + std::to_string(current);
|
||||
if ( ++current >= limit ) current = 0;
|
||||
auto& pod = uf::thread::get(thread);
|
||||
UF_ASSERT( std::this_thread::get_id() != pod.thread.get_id() );
|
||||
return pod;
|
||||
}
|
||||
pod::Thread::Tasks UF_API uf::thread::schedule( bool async, bool wait ) {
|
||||
return schedule( async ? uf::thread::workerThreadName : uf::thread::mainThreadName, wait );
|
||||
}
|
||||
pod::Thread::Tasks UF_API uf::thread::schedule( const uf::stl::string& name, bool wait ) {
|
||||
pod::Thread::Tasks tasks = {
|
||||
@ -69,16 +76,15 @@ pod::Thread::Tasks UF_API uf::thread::schedule( const uf::stl::string& name, boo
|
||||
return tasks;
|
||||
}
|
||||
void UF_API uf::thread::execute( pod::Thread::Tasks& tasks ) {
|
||||
if ( tasks.container.empty() ) return;
|
||||
if ( tasks.name == "Main" ) {
|
||||
// for ( auto& task : tasks.container ) task();
|
||||
if ( tasks.container.empty() ) return;
|
||||
if ( tasks.name == uf::thread::mainThreadName ) {
|
||||
while ( !tasks.container.empty() ) {
|
||||
auto& task = tasks.container.front();
|
||||
task();
|
||||
tasks.container.pop();
|
||||
}
|
||||
|
||||
} else if ( tasks.name == "Async" ) {
|
||||
#if 0
|
||||
} else /*if ( tasks.name == "Async" )*/ {
|
||||
uf::stl::vector<std::future<void>> futures;
|
||||
futures.reserve(tasks.container.size());
|
||||
// for ( auto& task : tasks.container ) {
|
||||
@ -88,9 +94,9 @@ void UF_API uf::thread::execute( pod::Thread::Tasks& tasks ) {
|
||||
tasks.container.pop();
|
||||
}
|
||||
if ( tasks.waits ) for ( auto& future : futures ) future.wait();
|
||||
#else
|
||||
} else {
|
||||
uf::stl::vector<pod::Thread*> workers;
|
||||
// for ( auto& task : tasks.container ) {
|
||||
while ( !tasks.container.empty() ) {
|
||||
auto task = tasks.container.front();
|
||||
auto& worker = uf::thread::fetchWorker( tasks.name );
|
||||
@ -100,6 +106,7 @@ void UF_API uf::thread::execute( pod::Thread::Tasks& tasks ) {
|
||||
}
|
||||
if ( tasks.waits ) for ( auto& worker : workers ) uf::thread::wait( *worker );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
void UF_API uf::thread::batchWorker( const pod::Thread::function_t& function, const uf::stl::string& name ) {
|
||||
@ -145,6 +152,7 @@ void UF_API uf::thread::queue( const pod::Thread::function_t& function ) {
|
||||
void UF_API uf::thread::queue( pod::Thread& thread, const pod::Thread::function_t& function ) {
|
||||
if ( thread.mutex != NULL ) thread.mutex->lock();
|
||||
thread.queue.emplace( function );
|
||||
thread.conditions.queued.notify_one();
|
||||
if ( thread.mutex != NULL ) thread.mutex->unlock();
|
||||
}
|
||||
void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(uf::thread::uid(thread)) ) { UF_THREAD_ANNOUNCE("Bad Thread: " << thread.uid << " " << thread.name); return; } //ops
|
||||
@ -174,12 +182,12 @@ void UF_API uf::thread::process( pod::Thread& thread ) { if ( !uf::thread::has(u
|
||||
}
|
||||
#endif
|
||||
}
|
||||
thread.condition.notify_one();
|
||||
thread.conditions.finished.notify_one();
|
||||
}
|
||||
void UF_API uf::thread::wait( pod::Thread& thread ) {
|
||||
if ( thread.mutex != NULL ) {
|
||||
std::unique_lock<std::mutex> lock(*thread.mutex);
|
||||
thread.condition.wait(lock, [&]{return thread.queue.empty();});
|
||||
thread.conditions.finished.wait(lock, [&]{return thread.queue.empty();});
|
||||
return;
|
||||
}
|
||||
while ( !thread.queue.empty() );
|
||||
@ -202,7 +210,7 @@ void UF_API uf::thread::terminate() {
|
||||
}
|
||||
}
|
||||
pod::Thread& UF_API uf::thread::create( const uf::stl::string& name, bool start, bool locks ) {
|
||||
if ( name == "Main" ) start = false;
|
||||
if ( name == uf::thread::mainThreadName ) start = false;
|
||||
|
||||
pod::Thread* pointer = NULL;
|
||||
uf::thread::threads.emplace_back(pointer = new pod::Thread);
|
||||
@ -213,14 +221,12 @@ pod::Thread& UF_API uf::thread::create( const uf::stl::string& name, bool start,
|
||||
static uint threads = std::thread::hardware_concurrency();
|
||||
thread.name = name;
|
||||
thread.uid = uids++;
|
||||
thread.terminates = false;
|
||||
thread.running = false;
|
||||
thread.mutex = NULL;
|
||||
thread.mutex = locks ? new std::mutex : NULL;
|
||||
thread.limiter = uf::thread::limiter;
|
||||
thread.affinity = (thread.uid % limit) + 1;
|
||||
|
||||
UF_THREAD_ANNOUNCE("Creating Thread #" << thread.uid << " (" << name << ") " << &thread << " (Affinity: " << thread.affinity << ") (Limiter: " << (1.0f / thread.limiter) << " FPS)" << (locks ? " with mutex" : ""));
|
||||
UF_THREAD_ANNOUNCE("Creating Thread #" << thread.uid << " (" << thread.name << " on core " << thread.affinity << ")" << (thread.limiter ? " (Limiter: " + std::to_string(1.0f / thread.limiter) + " FPS)" : ""));
|
||||
|
||||
if ( start ) uf::thread::start( thread );
|
||||
|
||||
|
||||
@ -127,9 +127,9 @@ SAVE: {
|
||||
UF_MSG_DEBUG("Baking...");
|
||||
|
||||
#if UF_BAKER_SAVE_MULTITHREAD
|
||||
auto tasks = uf::thread::schedule("Async");
|
||||
auto tasks = uf::thread::schedule(true);
|
||||
#else
|
||||
auto tasks = uf::thread::schedule("Main");
|
||||
auto tasks = uf::thread::schedule(false);
|
||||
#endif
|
||||
// 0 is always broken, do not save it
|
||||
for ( size_t i = 0; i < metadata.max.layers; ++i ) {
|
||||
|
||||
@ -195,7 +195,9 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
|
||||
pixels.insert( pixels.end(), p.begin(), p.end() );
|
||||
}
|
||||
// texture.mips = 0;
|
||||
texture.fromBuffers( (void*) pixels.data(), pixels.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, size.x, size.y, 1, filenames.size() );
|
||||
if ( size.x > 0 && size.y > 0 ) {
|
||||
texture.fromBuffers( (void*) pixels.data(), pixels.size(), uf::renderer::enums::Format::R8G8B8A8_UNORM, size.x, size.y, 1, filenames.size() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -633,7 +635,7 @@ void ext::ExtSceneBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali
|
||||
/*this->*/fog.density.multiplier = serializer["light"]["fog"]["density"]["multiplier"].as<float>();
|
||||
/*this->*/fog.density.scale = serializer["light"]["fog"]["density"]["scale"].as<float>();
|
||||
|
||||
/*this->*/sky.box.filename = serializer["sky"]["box"]["filename"].as<uf::stl::string>();
|
||||
/*this->*/sky.box.filename = serializer["sky"]["box"]["filename"].as<uf::stl::string>(sky.box.filename);
|
||||
|
||||
/*this->*/shader.mode = serializer["system"]["renderer"]["shader"]["mode"].as<uint32_t>();
|
||||
/*this->*/shader.scalar = serializer["system"]["renderer"]["shader"]["scalar"].as<uint32_t>();
|
||||
|
||||
32
ext/main.cpp
32
ext/main.cpp
@ -243,12 +243,12 @@ void EXT_API ext::initialize() {
|
||||
}
|
||||
|
||||
/* Frame limiter */ {
|
||||
float limit = configEngineLimitersJson["framerate"].as<float>();
|
||||
size_t limit = configEngineLimitersJson["framerate"].as<size_t>();
|
||||
::times.limiter = limit != 0 ? 1.0 / limit : 0;
|
||||
UF_MSG_DEBUG("Limiter set to " << ::times.limiter << "ms");
|
||||
}
|
||||
/* Max delta time */{
|
||||
float limit = configEngineLimitersJson["deltaTime"].as<float>();
|
||||
size_t limit = configEngineLimitersJson["deltaTime"].as<size_t>();
|
||||
uf::physics::time::clamp = limit != 0 ? 1.0 / limit : 0;
|
||||
}
|
||||
|
||||
@ -264,18 +264,12 @@ void EXT_API ext::initialize() {
|
||||
}
|
||||
|
||||
/* Thread frame limiter */ {
|
||||
float limit = configEngineThreadJson["frame limiter"].as<float>();
|
||||
size_t limit = configEngineThreadJson["frame limiter"].as<size_t>();
|
||||
uf::thread::limiter = limit != 0 ? 1.0 / limit : 0;
|
||||
}
|
||||
|
||||
// Set worker threads
|
||||
if ( configEngineThreadJson["workers"].as<uf::stl::string>() == "async" ) {
|
||||
uf::thread::async = true;
|
||||
auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ) / 2;
|
||||
configEngineThreadJson["workers"] = threads;
|
||||
uf::thread::workers = configEngineThreadJson["workers"].as<size_t>();
|
||||
UF_MSG_DEBUG("Using async worker threads");
|
||||
} else if ( configEngineThreadJson["workers"].as<uf::stl::string>() == "auto" ) {
|
||||
if ( configEngineThreadJson["workers"].as<uf::stl::string>() == "auto" ) {
|
||||
auto threads = std::max( 1, (int) std::thread::hardware_concurrency() - 1 ) / 2;
|
||||
configEngineThreadJson["workers"] = threads;
|
||||
uf::thread::workers = configEngineThreadJson["workers"].as<size_t>();
|
||||
@ -401,11 +395,12 @@ void EXT_API ext::initialize() {
|
||||
"deferred alias output to swapchain": false,
|
||||
*/
|
||||
|
||||
#if 1
|
||||
::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
|
||||
#if 0
|
||||
#else
|
||||
uf::renderer::settings::experimental::dedicatedThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
|
||||
uf::renderer::settings::experimental::rebuildOnTickBegin = configRenderExperimentalJson["rebuild on tick begin"].as( uf::renderer::settings::experimental::rebuildOnTickBegin );
|
||||
#endif
|
||||
uf::renderer::settings::experimental::rebuildOnTickBegin = configRenderExperimentalJson["rebuild on tick begin"].as( uf::renderer::settings::experimental::rebuildOnTickBegin );
|
||||
uf::renderer::settings::experimental::batchQueueSubmissions = configRenderExperimentalJson["batch queue submissions"].as( uf::renderer::settings::experimental::batchQueueSubmissions );
|
||||
|
||||
uf::renderer::settings::invariant::multithreadedRecording = configRenderInvariantJson["multithreaded recording"].as( uf::renderer::settings::invariant::multithreadedRecording );
|
||||
@ -492,7 +487,12 @@ void EXT_API ext::initialize() {
|
||||
renderMode.metadata.pipelines.emplace_back("culling");
|
||||
}
|
||||
}
|
||||
|
||||
#if UF_USE_VULKAN
|
||||
if ( ::json["engine"]["render modes"]["raytrace"].as<bool>(false) ) {
|
||||
auto* renderMode = new uf::renderer::RayTraceRenderMode;
|
||||
uf::renderer::addRenderMode( renderMode, "RayTrace" );
|
||||
}
|
||||
/* Callbacks for 2KHR stuffs */ {
|
||||
uf::hooks.addHook("vulkan:Instance.ExtensionsEnabled", []( const ext::json::Value& json ) {
|
||||
// UF_MSG_DEBUG("vulkan:Instance.ExtensionsEnabled: " << json);
|
||||
@ -556,7 +556,7 @@ void EXT_API ext::initialize() {
|
||||
uf::renderer::initialize();
|
||||
}
|
||||
|
||||
pod::Thread& threadMain = uf::thread::get("Main");
|
||||
pod::Thread& threadMain = uf::thread::get(uf::thread::mainThreadName);
|
||||
#if UF_USE_DISCORD
|
||||
/* Discord */ if ( ::config.engine.ext.discord.enabled ) {
|
||||
ext::discord::initialize();
|
||||
@ -585,7 +585,7 @@ void EXT_API ext::initialize() {
|
||||
};
|
||||
|
||||
if ( json["immediate"].as<bool>() ) function();
|
||||
else uf::thread::queue( uf::thread::get("Main"), function );
|
||||
else uf::thread::queue( uf::thread::get(uf::thread::mainThreadName), function );
|
||||
});
|
||||
|
||||
uf::hooks.addHook( "game:Scene.Cleanup", [&](ext::json::Value& json){
|
||||
@ -681,7 +681,7 @@ void EXT_API ext::tick() {
|
||||
}
|
||||
|
||||
/* Tick Main Thread Queue */ {
|
||||
uf::thread::process( uf::thread::get("Main") );
|
||||
uf::thread::process( uf::thread::get(uf::thread::mainThreadName) );
|
||||
}
|
||||
#if UF_USE_ULTRALIGHT
|
||||
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
|
||||
@ -733,7 +733,7 @@ void EXT_API ext::tick() {
|
||||
if ( ::requestDedicatedRenderThread ) {
|
||||
::requestDedicatedRenderThread = false;
|
||||
uf::renderer::settings::experimental::dedicatedThread = true;
|
||||
uf::renderer::settings::experimental::rebuildOnTickBegin = true;
|
||||
// uf::renderer::settings::experimental::rebuildOnTickBegin = true;
|
||||
UF_MSG_DEBUG("Dedicated render requested");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2,6 +2,6 @@ ARCH = win64
|
||||
CDIR =
|
||||
CC = gcc
|
||||
CXX = g++
|
||||
OPTIMIZATIONS = -g -O3 -fstrict-aliasing #-flto
|
||||
OPTIMIZATIONS = -O3 -g -fstrict-aliasing -DUF_NO_EXCEPTIONS #-flto
|
||||
WARNINGS = -Wall -Wno-unknown-pragmas -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-reorder -Wno-sign-compare -Wno-unused-but-set-variable -Wno-ignored-attributes -Wno-narrowing -Wno-misleading-indentation
|
||||
FLAGS += -std=c++20 $(OPTIMIZATIONS) $(WARNINGS) -fdiagnostics-color=always
|
||||
10
program.sh
10
program.sh
@ -1,4 +1,12 @@
|
||||
#!/bin/bash
|
||||
tskill program
|
||||
cd bin
|
||||
./program.bat $@ || tskill program
|
||||
|
||||
ARCH=$(cat ./exe/default/arch)
|
||||
CC=$(cat ./exe/default/cc)
|
||||
RENDERER=$(cat ./exe/default/renderer)
|
||||
|
||||
export PATH="$(pwd)/exe/lib/${ARCH}/:$(pwd)/exe/lib/${ARCH}/${CC}/${RENDERER}/:${PATH}"
|
||||
|
||||
./exe/program.${ARCH}.${CC}.${RENDERER}.exe $@
|
||||
tskill program
|
||||
|
||||
Loading…
Reference in New Issue
Block a user