finalized VR rendermode, rendertarget handles the camera for where it should render at (defaults to 3 units in front of camera), fixed flat GUI not clicking/hovering when in VR because of mismatched viewport sizes, fixed validation error regressions

This commit is contained in:
ecker 2026-06-23 21:51:01 -05:00
parent a98298b668
commit c3e337bb87
46 changed files with 418 additions and 296 deletions

View File

@ -6,7 +6,7 @@
"lightmaps": true,
"max": 32,
"shadows": {
"enabled": true,
"enabled": false,
"update": 4,
"max": 16,
"samples": 1
@ -110,7 +110,7 @@
"default defer buffer destroy": true,
"default command buffer immediate": true,
"n-buffered uniform": true,
"multithreaded recording": false
"multithreaded recording": true
},
"pipelines": {
"deferred": true,
@ -324,11 +324,7 @@
"preset": "native" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x)
},
"vr" : {
"enable" : true,
"manifest": "./data/openvr_manifest.json",
"swap eyes": false,
"dominant eye": 0,
"scale": 1.0
"enable" : false
},
"ultralight": { "enabled": true, "scale": 1.5 },
"discord": { "enabled": false },

View File

@ -12,6 +12,7 @@ layout (location = 1) in vec4 inColor;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
layout (binding = 0) uniform Camera {

View File

@ -14,6 +14,7 @@ layout (location = 3) in vec2 inOffset;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
layout (binding = 0) uniform Camera {

View File

@ -58,6 +58,7 @@ layout(binding = 10, set = 0, r32f) uniform writeonly image2DArray imageDepthRes
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
#include "../../../common/structs.h"

View File

@ -7,6 +7,7 @@ layout (location = 1) out flat uint outPass;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
void main() {

View File

@ -8,7 +8,7 @@ layout (location = 1) flat in uint inPass;
layout (location = 0) out vec4 outLeft;
layout (location = 1) out vec4 outRight;
layout (binding = 0) uniform sampler2D samplerColor;
layout (binding = 1) uniform sampler2D samplerColor;
layout(constant_id = 0) const int FORCE_OPAQUE = 0;
@ -19,6 +19,9 @@ layout(constant_id = 0) const int FORCE_OPAQUE = 0;
#include "../../common/functions.h"
void main() {
outLeft = vec4(0.0);
outRight = vec4(0.0);
vec4 outColor = texture( samplerColor, inUv );
if ( FORCE_OPAQUE == 1 ) outColor.a = 1;

View File

@ -10,14 +10,33 @@ layout (location = 1) out flat uint outPass;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
layout (binding = 0) uniform Camera {
layout (binding = 0) uniform UBO {
Viewport viewport[6];
} camera;
const vec2 positions[6] = vec2[](
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2(-1.0, 1.0),
vec2(-1.0, 1.0),
vec2( 1.0, -1.0),
vec2( 1.0, 1.0)
);
const vec2 uvs[6] = vec2[](
vec2(0.0, 0.0),
vec2(1.0, 0.0),
vec2(0.0, 1.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0),
vec2(1.0, 1.0)
);
void main() {
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
outUv = uvs[gl_VertexIndex];
outPass = PushConstant.pass;
gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f);
gl_Position = camera.viewport[PushConstant.pass].projection * camera.viewport[PushConstant.pass].view * vec4(positions[gl_VertexIndex], 0.0f, 1.0f);
}

View File

@ -8,7 +8,7 @@ layout (location = 1) flat in uint inPass;
layout (location = 0) out vec4 outLeft;
layout (location = 1) out vec4 outRight;
layout (binding = 0) uniform sampler2DArray samplerColor;
layout (binding = 1) uniform sampler2DArray samplerColor;
layout(constant_id = 0) const int FORCE_OPAQUE = 0;
@ -19,6 +19,9 @@ layout(constant_id = 0) const int FORCE_OPAQUE = 0;
#include "../../common/functions.h"
void main() {
outLeft = vec4(0.0);
outRight = vec4(0.0);
vec4 outColor = texture( samplerColor, vec3(inUv, inPass) );
if ( FORCE_OPAQUE == 1 ) outColor.a = 1;

View File

@ -7,10 +7,29 @@ layout (location = 1) out flat uint outPass;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
const vec2 positions[6] = vec2[](
vec2(-1.0, -1.0),
vec2( 1.0, -1.0),
vec2(-1.0, 1.0),
vec2(-1.0, 1.0),
vec2( 1.0, -1.0),
vec2( 1.0, 1.0)
);
const vec2 uvs[6] = vec2[](
vec2(0.0, 0.0),
vec2(1.0, 0.0),
vec2(0.0, 1.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0),
vec2(1.0, 1.0)
);
void main() {
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
outUv = uvs[gl_VertexIndex];
outPass = PushConstant.pass;
gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f);
gl_Position = vec4(positions[gl_VertexIndex], 0.0f, 1.0f);
}

View File

@ -57,6 +57,7 @@ bool projectSphere(vec3 C, float r, float znear, float P00, float P11, out vec4
layout( push_constant ) uniform PushBlock {
uint pass;
uint passes;
uint aux;
} PushConstant;
layout (binding = 0) uniform Camera {

View File

@ -8,6 +8,7 @@ layout (location = 3) in vec2 inOffset;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
struct Matrices {

View File

@ -28,6 +28,7 @@ layout (constant_id = 3) const uint CASCADES = 1;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
uint aux;
} PushConstant;
layout (binding = 0) uniform accelerationStructureEXT tlas;

View File

@ -139,6 +139,6 @@ namespace pod {
};
struct ImageStream {
StreamRegion buffer;
};
StreamRegion buffer;
};
}

View File

@ -15,7 +15,7 @@ namespace ext {
template<typename T>
sol::object getComponent( uf::Object& self ) {
return sol::make_object(ext::lua::state, std::ref(self.getComponent<T>()));
return sol::make_object(ext::lua::state, std::ref(self.getComponent<T>()));
}
}
}

View File

@ -45,7 +45,13 @@ namespace ext {
pod::Vector3f UF_API hmdEyePosition( vr::Hmd_Eye eye );
pod::Quaternion<> UF_API hmdQuaternion();
pod::Matrix4t<> UF_API hmdViewMatrix( vr::Hmd_Eye eye, const pod::Matrix4f& = uf::matrix::identity() );
pod::Matrix4t<> UF_API hmdProjectionMatrix( vr::Hmd_Eye, float = 0.1f, float = 1024.0f );
pod::Matrix4t<> UF_API hmdProjectionMatrix( vr::Hmd_Eye, float = 0.001f, float = 0.0f );
inline pod::Matrix4t<> UF_API hmdViewMatrix( int i, const pod::Matrix4f& m = uf::matrix::identity() ) {
return hmdViewMatrix( i == 0 ? vr::Eye_Left : vr::Eye_Right, m );
}
inline pod::Matrix4t<> UF_API hmdProjectionMatrix( int i, float zNear = 0.001f, float zFar = 0.0f ) {
return hmdProjectionMatrix( i == 0 ? vr::Eye_Left : vr::Eye_Right, zNear, zFar );
}
uf::Serializer UF_API controllerState( vr::Controller_Hand, const uf::stl::string& = "" );
pod::Vector3f UF_API controllerPosition( vr::Controller_Hand, bool = false );

View File

@ -2,6 +2,7 @@
#include <uf/utils/mesh/mesh.h>
#include <uf/utils/image/image.h>
#include <uf/utils/camera/camera.h>
#include <uf/ext/vulkan/device.h>
#include <uf/ext/vulkan/buffer.h>
#include <uf/ext/vulkan/texture.h>
@ -40,7 +41,6 @@ namespace ext {
uf::stl::string target = "";
uf::stl::string pipeline = "";
uf::stl::vector<uf::stl::string> pipelines;
// uf::stl::vector<uint8_t> outputs;
uf::stl::unordered_map<uf::stl::string, uint8_t> attachments;
uf::stl::unordered_map<uf::stl::string, uint8_t> buffers;
@ -57,6 +57,7 @@ namespace ext {
uint8_t views = 1;
bool compute = false;
uf::Camera camera;
} metadata;
Device* device = VK_NULL_HANDLE;

View File

@ -12,6 +12,7 @@ namespace ext {
virtual GraphicDescriptor bindGraphicDescriptor( const GraphicDescriptor&, size_t = 0 );
virtual void build( bool = true );
virtual void tick();
virtual VkSubmitInfo queue();
virtual void render();
virtual void destroy();
};

View File

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

View File

@ -11,11 +11,11 @@
namespace pod {
struct ZipEntry {
size_t offset;
size_t compressedSize;
size_t uncompressedSize;
uint16_t compressionMethod;
};
size_t offset;
size_t compressedSize;
size_t uncompressedSize;
uint16_t compressionMethod;
};
}
namespace ext {

View File

@ -15,11 +15,11 @@ namespace uf {
namespace pod {
struct UF_API Camera {
pod::Transform<> transform;
pod::Transform<> transform = {};
struct Viewports {
struct Matrices{
pod::Matrix4f view;
pod::Matrix4f projection;
pod::Matrix4f view = uf::matrix::identity();
pod::Matrix4f projection = uf::matrix::identity();
} matrices[uf::camera::maxViews];
} viewport;
size_t views = 1;

View File

@ -11,10 +11,10 @@ namespace pod {
END,
};
pod::Checkpoint::Type type = Type::GENERIC;
pod::Checkpoint::Type type = Type::GENERIC;
uf::stl::string name = "";
uf::stl::string info = "";
pod::Checkpoint* previous = NULL;
pod::Checkpoint* previous = NULL;
};
}

View File

@ -6,7 +6,7 @@ template <typename R, typename ... Args> constexpr bool return_void(R(Args ...))
template <typename Signature> struct count_args;
template <typename Ret, typename... Args> struct count_args<std::function<Ret(Args...)>> {
static constexpr size_t value = sizeof...(Args);
static constexpr size_t value = sizeof...(Args);
};
// For generic types that are functors, delegate to its 'operator()'
@ -16,14 +16,14 @@ struct function_traits : public function_traits<decltype(&T::operator())> {};
// for pointers to member function
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const> {
//enum { arity = sizeof...(Args) };
static const size_t arguments = sizeof...(Args);
template <size_t i>
//enum { arity = sizeof...(Args) };
static const size_t arguments = sizeof...(Args);
template <size_t i>
struct Arg {
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
typedef ReturnType return_type;
typedef std::function<ReturnType (Args...)> type;
typedef ReturnType return_type;
typedef std::function<ReturnType (Args...)> type;
};
// for pointers to member function
@ -34,8 +34,8 @@ struct function_traits<ReturnType(ClassType::*)(Args...) > {
struct Arg {
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
typedef ReturnType return_type;
typedef std::function<ReturnType (Args...)> type;
typedef ReturnType return_type;
typedef std::function<ReturnType (Args...)> type;
};
// for function pointers

View File

@ -1,6 +1,6 @@
#define UF_VFS_MOUNT_CPP( LAMBDA, URI, PRIORITY ) \
namespace {\
static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\
uf::vfs::mount( LAMBDA( URI, PRIORITY ) );\
});\
static uf::StaticInitialization TOKEN_PASTE(STATIC_INITIALIZATION_, __LINE__)( []{\
uf::vfs::mount( LAMBDA( URI, PRIORITY ) );\
});\
}

View File

@ -32,18 +32,18 @@ namespace uf {
namespace vfs {
extern UF_API uf::stl::vector<pod::Mount> mounts;
size_t UF_API mount( const pod::Mount& mount );
bool UF_API unmount( size_t );
bool UF_API unmount( const uf::stl::string& prefix, const uf::stl::string& base );
size_t UF_API mount( const pod::Mount& mount );
bool UF_API unmount( size_t );
bool UF_API unmount( const uf::stl::string& prefix, const uf::stl::string& base );
bool UF_API exists( const uf::stl::string& path );
bool UF_API exists( const uf::stl::string& path );
size_t UF_API size( const uf::stl::string& path );
size_t UF_API mtime( const uf::stl::string& path );
bool UF_API read( const uf::stl::string& path, uf::stl::vector<uint8_t>& buffer );
size_t UF_API write( const uf::stl::string& path, const void* data, size_t len );
size_t UF_API write( const uf::stl::string& path, uf::stl::vector<uint8_t>& buffer );
bool UF_API mkdir( const uf::stl::string& path );
bool UF_API read( const uf::stl::string& path, uf::stl::vector<uint8_t>& buffer );
size_t UF_API write( const uf::stl::string& path, const void* data, size_t len );
size_t UF_API write( const uf::stl::string& path, uf::stl::vector<uint8_t>& buffer );
bool UF_API mkdir( const uf::stl::string& path );
bool UF_API readRange( const uf::stl::string& path, size_t start, size_t len, uf::stl::vector<uint8_t>& buffer );
bool UF_API readRanges( const uf::stl::string& path, const uf::stl::vector<pod::Range>& ranges, uf::stl::vector<uint8_t>& buffer );

View File

@ -3,22 +3,22 @@
#include "../structs.h"
namespace impl {
void solve1DLinearMotor(
pod::PhysicsBody& a, pod::PhysicsBody& b,
const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& axis,
float targetVelocity, float maxForce, float& accumulatedImpulse, float dt
);
void solve1DAngularMotor(
pod::PhysicsBody& a, pod::PhysicsBody& b,
const pod::Vector3f& axis,
float targetVelocity, float maxTorque,
float& accumulatedImpulse, float dt
);
void solve1DLinearMotor(
pod::PhysicsBody& a, pod::PhysicsBody& b,
const pod::Vector3f& rA, const pod::Vector3f& rB, const pod::Vector3f& axis,
float targetVelocity, float maxForce, float& accumulatedImpulse, float dt
);
void solve1DAngularMotor(
pod::PhysicsBody& a, pod::PhysicsBody& b,
const pod::Vector3f& axis,
float targetVelocity, float maxTorque,
float& accumulatedImpulse, float dt
);
}
namespace uf {
namespace physics {
pod::Constraint& UF_API constrainMotor( pod::Constraint& constraint, float targetVelocity, float maxForceOrTorque );
}
namespace physics {
pod::Constraint& UF_API constrainMotor( pod::Constraint& constraint, float targetVelocity, float maxForceOrTorque );
}
}

View File

@ -330,8 +330,8 @@ namespace pod {
MASK_NONE = 0,
MASK_STATIC = CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_PROJECTILE,
MASK_DYNAMIC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC | CATEGORY_TRIGGER,
MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE | CATEGORY_TRIGGER,
MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE | CATEGORY_TRIGGER,
MASK_PLAYER = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_NPC | CATEGORY_PROJECTILE | CATEGORY_TRIGGER,
MASK_NPC = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_PROJECTILE | CATEGORY_TRIGGER,
MASK_TRIGGER = CATEGORY_PLAYER | CATEGORY_NPC,
MASK_PROJECTILE = CATEGORY_STATIC | CATEGORY_DYNAMIC | CATEGORY_PLAYER | CATEGORY_NPC,
MASK_CHARACTER = MASK_PLAYER | MASK_NPC,

View File

@ -122,8 +122,8 @@ template<typename T>
pod::Transform<T> uf::transform::fromMatrix( const pod::Matrix4t<T>& matrix ) {
pod::Transform<T> transform;
transform.position = uf::matrix::extractTranslation( matrix );
transform.orientation = uf::quaternion::fromMatrix( matrix );
transform.scale = uf::matrix::extractScale( matrix );
transform.orientation = uf::quaternion::fromMatrix( matrix );
transform.scale = uf::matrix::extractScale( matrix );
return transform;
}

View File

@ -8,12 +8,12 @@
namespace uf {
namespace stl {
template<
class T,
#if UF_MEMORYPOOL_OVERRIDE_NEW_DELETE
class Allocator = std::allocator<T>
#else
class Allocator = uf::Allocator<T>
#endif
class T,
#if UF_MEMORYPOOL_OVERRIDE_NEW_DELETE
class Allocator = std::allocator<T>
#else
class Allocator = uf::Allocator<T>
#endif
>
using deque = std::deque<T, Allocator>;
}

View File

@ -52,9 +52,9 @@ namespace pod {
} segregated;
struct {
void* freeLists[32];
uint8_t* splitBlockBitset;
size_t maxLevel;
size_t minBlockSize;
uint8_t* splitBlockBitset;
size_t maxLevel;
size_t minBlockSize;
} buddy;
} state;

View File

@ -9,8 +9,8 @@
namespace uf {
namespace stl {
template<
class T,
class Container = uf::stl::deque<T>
class T,
class Container = uf::stl::deque<T>
>
using queue = std::queue<T, Container>;
}

View File

@ -9,8 +9,8 @@
namespace uf {
namespace stl {
template<
class T,
class Container = uf::stl::deque<T>
class T,
class Container = uf::stl::deque<T>
>
using stack = std::stack<T, Container>;
}

View File

@ -1,6 +1,8 @@
#pragma once
#include <uf/config.h>
#include <uf/utils/memory/map.h>
#include <memory>
#include "thread.h"
namespace uf {
@ -8,20 +10,22 @@ namespace uf {
class UF_API ThreadUnique {
public:
typedef T type_t;
typedef std::mutex* mutex_type_t;
typedef std::shared_ptr<std::mutex> mutex_type_t;
typedef std::thread::id id_t;
typedef uf::stl::unordered_map<id_t, type_t> container_t;
typedef uf::stl::unordered_map<id_t, mutex_type_t> mutex_container_t;
typedef uf::stl::map<id_t, type_t> container_t;
typedef uf::stl::map<id_t, mutex_type_t> mutex_container_t;
protected:
container_t m_container;
mutex_container_t m_mutex_container;
mutex_type_t m_mutex;
public:
~ThreadUnique();
ThreadUnique() : m_mutex(std::make_shared<std::mutex>()) {}
bool has( id_t id = std::this_thread::get_id() ) const;
T& get( id_t id = std::this_thread::get_id() );
container_t& container();
mutex_type_t getMutex( id_t id = std::this_thread::get_id() );
void lockMutex( id_t id = std::this_thread::get_id() );
bool tryMutex( id_t id = std::this_thread::get_id() );
void unlockMutex( id_t id = std::this_thread::get_id() );

View File

@ -1,52 +1,47 @@
template<typename T>
uf::ThreadUnique<T>::~ThreadUnique() {
for ( auto& pair : m_mutex_container ) {
if ( !pair.second ) continue;
delete pair.second;
pair.second = NULL;
}
}
template<typename T>
bool uf::ThreadUnique<T>::has( id_t id ) const {
std::lock_guard<std::mutex> lock(*m_mutex);
return m_container.count(id) > 0;
}
template<typename T>
T& uf::ThreadUnique<T>::get( id_t id ) {
std::lock_guard<std::mutex> lock(*m_mutex);
return m_container[id];
}
template<typename T>
uf::ThreadUnique<T>::mutex_type_t uf::ThreadUnique<T>::getMutex( id_t id ) {
std::lock_guard<std::mutex> lock(*m_mutex);
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = std::make_shared<std::mutex>();
return m_mutex_container[id];
}
template<typename T>
void uf::ThreadUnique<T>::lockMutex( id_t id ) {
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
m_mutex_container[id]->lock();
getMutex( id )->lock();
}
template<typename T>
bool uf::ThreadUnique<T>::tryMutex( id_t id ) {
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
return m_mutex_container[id]->try_lock();
return getMutex( id )->try_lock();
}
template<typename T>
void uf::ThreadUnique<T>::unlockMutex( id_t id ) {
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
m_mutex_container[id]->unlock();
getMutex( id )->unlock();
}
template<typename T>
std::lock_guard<std::mutex> uf::ThreadUnique<T>::guardMutex( id_t id ) {
if ( m_mutex_container.count(id) == 0 ) m_mutex_container[id] = new std::mutex;
return std::lock_guard<std::mutex>(*m_mutex_container[id]);
return std::lock_guard<std::mutex>(*getMutex( id ));
}
template<typename T>
void uf::ThreadUnique<T>::cleanup( id_t id ) {
std::lock_guard<std::mutex> lock(*m_mutex);
for ( auto it = m_container.begin(); it != m_container.end(); ) {
if ( it->first == id ) ++it;
else it = m_container.erase(it);
if ( it->first == id ) it = m_container.erase(it);
else ++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);
}
if ( it->first == id ) it = m_mutex_container.erase(it);
else ++it;
}
}
template<typename T>

View File

@ -376,11 +376,6 @@ void UF_API uf::load( ext::json::Value& json ) {
}
#endif
#if 0 && UF_USE_OPENVR
static auto* vrRenderMode = new ext::vulkan::VrRenderMode;
uf::renderer::addRenderMode(vrRenderMode, "VR");
#endif
// shouldn't ever fire because the deferred rendermode is owned by the scene now
if ( uf::renderer::hasRenderMode("", true) ) {
auto& renderMode = uf::renderer::getRenderMode("", true);
@ -677,6 +672,10 @@ void UF_API uf::initialize() {
ext::openvr::recommendedResolution( uf::renderer::settings::width, uf::renderer::settings::height );
UF_MSG_DEBUG("VR Resolution: {}, {}", uf::renderer::settings::width, uf::renderer::settings::height);
}
// could probably live alongside gui/deferred in the scene
static auto* vrRenderMode = new ext::vulkan::VrRenderMode;
uf::renderer::addRenderMode(vrRenderMode, "VR");
}
#endif
@ -987,11 +986,6 @@ void UF_API uf::render() {
// uf::renderer::tick();
uf::renderer::render();
}
#if UF_USE_OPENVR
if ( !uf::renderer::hasRenderMode("VR") ) {
ext::openvr::submit();
}
#endif
}
void UF_API uf::terminate() {
/* Kill threads */ {

View File

@ -243,10 +243,6 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
auto anchor = ::parseAnchor( metadata.anchor, metadata.pivot ) * 2.0f - 1.0f;
transform.position.x += anchor.x;
transform.position.y += anchor.y;
/*
transform.position.x += anchor.x * ((float) metadata.size.x / uf::renderer::settings::width) * transform.scale.x;
transform.position.y += anchor.y * ((float) metadata.size.y / uf::renderer::settings::height) * transform.scale.y;
*/
}
@ -280,7 +276,11 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
if ( metadata.space != "screen" ) return;
if ((metadata.boxMin.x > metadata.boxMax.x)||(metadata.boxMin.y > metadata.boxMax.y)) return;
#if UF_USE_OPENVR
pod::Vector2ui guiSize = uf::renderer::device.window->getSize();
#else
pod::Vector2ui guiSize = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
#endif
bool clicked = false;
if ( payload.mouse.state == -1 ) {
@ -372,7 +372,11 @@ void ext::GuiBehavior::initialize( uf::Object& self ) {
if ( metadata.space != "screen" ) return;
if ((metadata.boxMin.x > metadata.boxMax.x)||(metadata.boxMin.y > metadata.boxMax.y)) return;
#if UF_USE_OPENVR
pod::Vector2ui guiSize = uf::renderer::device.window->getSize();
#else
pod::Vector2ui guiSize = pod::Vector2ui{ uf::renderer::settings::width, uf::renderer::settings::height };
#endif
bool hovered = false;
pod::Vector2f click;
@ -469,7 +473,11 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
auto& camera = controller.getComponent<uf::Camera>();
if ( metadata.space == "screen" ) {
#if UF_USE_OPENVR
pod::Vector2ui guiSize = uf::renderer::device.window->getSize();
#else
pod::Vector2f guiSize = pod::Vector2f{ uf::renderer::settings::width, uf::renderer::settings::height };
#endif
pod::Vector2f scale = { 1, 1 };
if ( metadata.scaling == "fixed" || metadata.scaling == "fixed-x" ) scale.x = (float) metadata.size.x / guiSize.x;

View File

@ -15,6 +15,7 @@
#include <uf/utils/math/physics.h>
#include <uf/spec/controller/controller.h>
#include <uf/utils/io/inputs.h>
#include <uf/ext/openvr/openvr.h>
#include "../../scene/behavior.h"
@ -60,7 +61,13 @@ void ext::PlayerCameraBehavior::initialize( uf::Object& self ) {
size = uf::vector::decode(uf::config["window"]["size"], pod::Vector2ui{});
raidou = (float) size.x / (float) size.y;
}
camera.setProjection( uf::matrix::perspective( fov, raidou, range.x, range.y ) );
if ( ext::openvr::enabled ) {
camera.setProjection( ext::openvr::hmdProjectionMatrix(0, range.x, range.y), 0 );
camera.setProjection( ext::openvr::hmdProjectionMatrix(1, range.x, range.y), 1 );
} else {
camera.setProjection( uf::matrix::perspective( fov, raidou, range.x, range.y ) );
}
}
camera.update();

View File

@ -25,9 +25,7 @@ void uf::SceneBehavior::initialize( uf::Object& self ) {
});
uf::physics::initialize( self );
UF_MSG_DEBUG("Initializing graph...");
uf::graph::initialize( self );
UF_MSG_DEBUG("Initialized graph.");
auto& metadata = this->getComponent<uf::SceneBehavior::Metadata>();
}

View File

@ -408,7 +408,9 @@ bool ext::openvr::requestRenderModel( const uf::stl::string& name ) {
return false;
}
void ext::openvr::submit() {
if ( !g_vr.system ) return;
if ( !g_vr.system ) {
return;
}
#if UF_USE_VULKAN
bool invert = g_vr.swapEyes;
@ -421,12 +423,16 @@ void ext::openvr::submit() {
} else {
renderModePointer = &uf::renderer::getRenderMode("", true);
}
if ( !renderModePointer ) return;
if ( !renderModePointer ) {
return;
}
auto& renderMode = *renderModePointer;
float width = renderMode.width > 0 ? renderMode.width : uf::renderer::settings::width;
float height = renderMode.height > 0 ? renderMode.height : uf::renderer::settings::height;
if ( !renderMode.hasAttachment("left") || !renderMode.hasAttachment("right") ) return;
if ( !renderMode.hasAttachment("left") || !renderMode.hasAttachment("right") ) {
return;
}
auto& leftEyeAttachment = renderMode.getAttachment("left");
auto& rightEyeAttachment = renderMode.getAttachment("right");
@ -452,19 +458,19 @@ void ext::openvr::submit() {
vr::EVRCompositorError err;
vulkanData.m_nFormat = leftEyeAttachment.descriptor.format;
vulkanData.m_nImage = (uint64_t) (VkImage) leftEyeAttachment.image;
VR_CHECK_COMPOSITOR_RESULT(vr::VRCompositor()->Submit( invert ? vr::Eye_Right : vr::Eye_Left, &texture, &bounds ));
VR_CHECK_COMPOSITOR_RESULT(g_vr.compositor->Submit( invert ? vr::Eye_Right : vr::Eye_Left, &texture, &bounds ));
vulkanData.m_nFormat = rightEyeAttachment.descriptor.format;
vulkanData.m_nImage = (uint64_t) (VkImage) rightEyeAttachment.image;
VR_CHECK_COMPOSITOR_RESULT(vr::VRCompositor()->Submit( invert ? vr::Eye_Left : vr::Eye_Right, &texture, &bounds ));
VR_CHECK_COMPOSITOR_RESULT(g_vr.compositor->Submit( invert ? vr::Eye_Left : vr::Eye_Right, &texture, &bounds ));
vr::VRCompositor()->PostPresentHandoff();
g_vr.compositor->PostPresentHandoff();
#endif
}
void ext::openvr::synchronize() {
if ( !g_vr.system ) return;
vr::VRCompositor()->WaitGetPoses(nullptr, 0, nullptr, 0);
g_vr.compositor->WaitGetPoses(nullptr, 0, nullptr, 0);
updateTracking(1);
}
float ext::openvr::predictedTimeToDisplay( float additional ) {
@ -545,6 +551,25 @@ pod::Matrix4t<> ext::openvr::hmdProjectionMatrix( vr::Hmd_Eye eye, float zNear,
float idx = 1.0f / (right - left);
float idy = 1.0f / (bottom - top);
m(0,0) = 2.0f * idx;
m(1,1) = -2.0f * idy;
m(0,2) = (right + left) * idx;
m(1,2) = -(bottom + top) * idy;
m(3,2) = 1.0f;
m(3,3) = 0.0f;
if ( zFar <= 0.0f) {
m(2,2) = 0.0f;
m(2,3) = zNear;
} else {
float range = zFar - zNear;
m(2,2) = zFar / range;
m(2,3) = -(zFar * zNear) / range;
}
/*
float idx = 1.0f / (right - left);
float idy = 1.0f / (bottom - top);
m(0,0) = 2.0f * idx;
m(1,1) = 2.0f * idy;
m(0,2) = (right + left) * idx;
@ -560,6 +585,7 @@ pod::Matrix4t<> ext::openvr::hmdProjectionMatrix( vr::Hmd_Eye eye, float zNear,
m(2,2) = zFar / range;
m(2,3) = -(zFar * zNear) / range;
}
*/
return m;
}

View File

@ -824,7 +824,7 @@ VkCommandPool ext::vulkan::Device::getCommandPool( ext::vulkan::QueueEnum queueE
break;
}
UF_ASSERT( commandPool );
auto guard = commandPool->guardMutex();
auto guard = commandPool->guardMutex(id);
bool exists = commandPool->has(id);
VkCommandPool& pool = commandPool->get(id);
if ( !exists ) {
@ -873,7 +873,7 @@ VkQueue ext::vulkan::Device::getQueue( ext::vulkan::QueueEnum queueEnum, std::th
break;
}
UF_ASSERT( commandPool );
auto guard = commandPool->guardMutex();
auto guard = commandPool->guardMutex(id);
bool exists = commandPool->has(id);
VkQueue& queue = commandPool->get(id);
if ( !exists ) {

View File

@ -259,7 +259,7 @@ ext::vulkan::RenderMode::commands_container_t& ext::vulkan::RenderMode::getComma
commands.resize( swapchain.buffers );
VkCommandBufferAllocateInfo cmdBufAllocateInfo = ext::vulkan::initializers::commandBufferAllocateInfo(
device->getCommandPool(this->queueEnum),
device->getCommandPool(this->queueEnum, id),
VK_COMMAND_BUFFER_LEVEL_PRIMARY,
static_cast<uint32_t>(commands.size())
);
@ -286,8 +286,11 @@ void ext::vulkan::RenderMode::cleanupAllCommands() {
if ( pair.second.empty() ) continue;
VkQueue queue = device->getQueue( queueEnum, pair.first );
vkQueueWaitIdle( queue );
/*
VkResult res = vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT );
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
*/
for ( auto& commandBuffer : pair.second ) {
uf::checkpoint::deallocate(device->checkpoints[commandBuffer]);
@ -306,9 +309,13 @@ void ext::vulkan::RenderMode::cleanupCommands( std::thread::id id ) {
if ( pair.first == id ) continue;
if ( pair.second.empty() ) continue;
VkQueue queue = device->getQueue( queueEnum, pair.first );
vkQueueWaitIdle( queue );
/*
VkResult res = vkWaitForFences( *device, fences.size(), fences.data(), VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT );
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
*/
for ( auto& commandBuffer : pair.second ) {
uf::checkpoint::deallocate(device->checkpoints[commandBuffer]);
@ -425,10 +432,11 @@ void ext::vulkan::RenderMode::initialize( Device& device ) {
if ( std::find( metadata.pipelines.begin(), metadata.pipelines.end(), metadata.pipeline ) == metadata.pipelines.end() ) {
metadata.pipelines.emplace_back(metadata.pipeline);
}
/*
if ( !this->hasBuffer("camera") ) {
this->metadata.buffers["camera"] = this->initializeBuffer( (const void*) nullptr, sizeof(pod::Camera::Viewports), uf::renderer::enums::Buffer::UNIFORM );
}
*/
}
void ext::vulkan::RenderMode::build( bool resized ) {
@ -436,12 +444,10 @@ void ext::vulkan::RenderMode::build( bool resized ) {
}
void ext::vulkan::RenderMode::tick() {
if ( ext::vulkan::states::resized || uf::renderer::states::rebuild || rebuild ) {
//if ( device ) vkDeviceWaitIdle(*device);
synchronize();
cleanupAllCommands();
}
//this->synchronize();
if ( metadata.limiter.frequency > 0 ) {
if ( metadata.limiter.timer > metadata.limiter.frequency ) {
metadata.limiter.timer = 0;

View File

@ -9,6 +9,10 @@
#include <uf/utils/graphic/graphic.h>
#include <uf/utils/io/fmt.h>
namespace {
uint32_t imageIndex;
}
const uf::stl::string ext::vulkan::BaseRenderMode::getType() const {
return "Swapchain";
}
@ -109,12 +113,28 @@ void ext::vulkan::BaseRenderMode::tick() {
this->build( resized );
}
}
VkSubmitInfo ext::vulkan::BaseRenderMode::queue() {
auto& commands = getCommands( this->mostRecentCommandPoolId );
static VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = waitStageMask;
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[states::currentBuffer];
submitInfo.waitSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[::imageIndex];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
submitInfo.commandBufferCount = 1;
return submitInfo;
}
void ext::vulkan::BaseRenderMode::render() {
// if ( this->commands.container().empty() ) return;
uint32_t imageIndex;
VK_CHECK_RESULT(vkWaitForFences(*device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
VK_CHECK_RESULT(swapchain.acquireNextImage(&imageIndex, swapchain.presentCompleteSemaphores[states::currentBuffer]));
VK_CHECK_RESULT(swapchain.acquireNextImage(&::imageIndex, swapchain.presentCompleteSemaphores[states::currentBuffer]));
VK_CHECK_RESULT(vkResetFences(*device, 1, &fences[states::currentBuffer]));
auto& commands = getCommands( this->mostRecentCommandPoolId );
@ -200,7 +220,7 @@ void ext::vulkan::BaseRenderMode::render() {
scissor.offset.x = 0;
scissor.offset.y = 0;
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[imageIndex];
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[::imageIndex];
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "begin" );
@ -244,25 +264,14 @@ void ext::vulkan::BaseRenderMode::render() {
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
}
VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = waitStageMask;
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[states::currentBuffer];
submitInfo.waitSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[imageIndex];
submitInfo.signalSemaphoreCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
submitInfo.commandBufferCount = 1;
{
VkSubmitInfo submitInfo = this->queue();
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, fences[states::currentBuffer]);
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
}
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), imageIndex, renderCompleteSemaphores[imageIndex]));
VK_CHECK_RESULT(swapchain.queuePresent(device->getQueue( QueueEnum::PRESENT ), ::imageIndex, renderCompleteSemaphores[::imageIndex]));
states::currentBuffer = (states::currentBuffer + 1) % ext::vulkan::swapchain.buffers;
this->executed = true;

View File

@ -367,7 +367,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
shader.aliasAttachment("uv", this);
shader.aliasAttachment("normal", this);
#endif
shader.aliasAttachment("depth", this);
shader.aliasAttachment("depth", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
@ -415,7 +415,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "dof-down");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("depth_resolved", this);
shader.aliasAttachment("depth_resolved", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
// atomic counter buffer
@ -432,7 +432,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "dof-up");
shader.aliasAttachment("color", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("depth_resolved", this);
shader.aliasAttachment("depth_resolved", this, VK_IMAGE_LAYOUT_GENERAL);
shader.aliasAttachment("scratch", this, VK_IMAGE_LAYOUT_GENERAL);
{
@ -449,7 +449,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("compute", "depth-pyramid");
shader.aliasAttachment("depth_resolved", this);
shader.aliasAttachment("depth_resolved", this, VK_IMAGE_LAYOUT_GENERAL);
// atomic counter buffer
::postprocesses::depthPyramid.atomicCounter.initialize( (const void*) nullptr, sizeof(::AtomicCounter) * 1, uf::renderer::enums::Buffer::STORAGE | VK_BUFFER_USAGE_TRANSFER_DST_BIT );
@ -617,6 +617,10 @@ void ext::vulkan::DeferredRenderMode::build( bool resized ) {
if ( ext::openvr::enabled ) {
auto descriptor = blitter.descriptor;
descriptor.pipeline = "vr";
descriptor.renderMode = "VR";
descriptor.bind.point = VK_PIPELINE_BIND_POINT_GRAPHICS;
descriptor.depth.test = false;
descriptor.cullMode = uf::renderer::enums::CullMode::NONE;
blitter.update( descriptor );
}
}
@ -657,56 +661,33 @@ void ext::vulkan::DeferredRenderMode::tick() {
}
}
VkSubmitInfo ext::vulkan::DeferredRenderMode::queue() {
//lockMutex( this->mostRecentCommandPoolId );
auto& commands = getCommands( this->mostRecentCommandPoolId );
// Pipeline stage at which the queue submission will wait (via pWaitSemaphores)
static VkPipelineStageFlags waitStageMask[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
// The submit info structure specifices a command buffer queue submission batch
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = waitStageMask; // Pointer to the list of pipeline stages that the semaphore waits will occur at
submitInfo.pWaitSemaphores = &swapchain.presentCompleteSemaphores[states::currentBuffer]; // Semaphore(s) to wait upon before the submitted command buffer starts executing
submitInfo.waitSemaphoreCount = 1; // One wait semaphore
submitInfo.pSignalSemaphores = &renderCompleteSemaphores[states::currentBuffer]; // Semaphore(s) to be signaled when command buffers have completed
submitInfo.signalSemaphoreCount = 1; // One signal semaphore
submitInfo.pCommandBuffers = &commands[states::currentBuffer]; // Command buffers(s) to execute in this batch (submission)
submitInfo.pWaitDstStageMask = NULL;
submitInfo.pWaitSemaphores = NULL;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pSignalSemaphores = NULL;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
submitInfo.commandBufferCount = 1;
return submitInfo;
}
void ext::vulkan::DeferredRenderMode::render() {
// if ( this->executed ) return;
//lockMutex( this->mostRecentCommandPoolId );
if ( this->commands.container().empty() ) return;
auto& commands = getCommands( this->mostRecentCommandPoolId );
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_BEGIN, VkCommandBuffer{}, 0, {} );
// Submit commands
// Use a fence to ensure that command buffer has finished executing before using it again
/*
VK_CHECK_RESULT(vkWaitForFences( *device, 1, &fences[states::currentBuffer], VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT ));
VK_CHECK_RESULT(vkResetFences( *device, 1, &fences[states::currentBuffer] ));
*/
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
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( QueueEnum::GRAPHICS ), 1, &submitInfo, fences[states::currentBuffer]));
VkSubmitInfo submitInfo = this->queue();
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, VK_NULL_HANDLE/*fences[states::currentBuffer]*/);
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_END, VkCommandBuffer{}, 0, {} );
this->executed = true;
//unlockMutex( this->mostRecentCommandPoolId );
}
void ext::vulkan::DeferredRenderMode::destroy() {
forwardRenderTarget.destroy();
@ -899,7 +880,7 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
clearRect.rect.offset = { 0, 0 };
clearRect.rect.extent = { width, height };
clearRect.baseArrayLayer = 0;
clearRect.layerCount = metadata.eyes > 0 ? metadata.eyes : 1;
clearRect.layerCount = 1;
vkCmdClearAttachments(commandBuffer, 1, &clearDepth, 1, &clearRect);
}
@ -1204,70 +1185,57 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
#endif
}
/*
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
{
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "fsr:start" );
ext::fsr::render( commandBuffer );
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "fsr:end" );
}
#endif
*/
#if UF_USE_OPENVR
// OpenVR does not respect layered images
if ( metadata.eyes == 2 && !ext::vulkan::hasRenderMode("VR") ) {
auto& outputAttachment = this->getAttachment("left");
auto& scratchAttachment = this->getAttachment("right");
if ( metadata.eyes == 2 ) {
if ( ext::vulkan::hasRenderMode("VR") ) {
/*
// transition outputs
auto& outputAttachment = this->getAttachment("output");
VkImageSubresourceRange outRange = {};
outRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
outRange.baseMipLevel = 0;
outRange.levelCount = 1;
outRange.baseArrayLayer = 0;
outRange.layerCount = metadata.eyes;
VkImageSubresourceRange range = {};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = metadata.eyes;
VkImageSubresourceRange scratchRange = outRange;
scratchRange.layerCount = 1;
uf::renderer::Texture::setImageLayout( commandBuffer, outputAttachment.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, range );
*/
} else {
// OpenVR does not respect layered images
auto& outputAttachment = this->getAttachment("left");
auto& scratchAttachment = this->getAttachment("right");
uf::renderer::Texture::setImageLayout(
commandBuffer, outputAttachment.image,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // Or SHADER_READ_ONLY
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
outRange
);
uf::renderer::Texture::setImageLayout(
commandBuffer, scratchAttachment.image,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
scratchRange
);
VkImageSubresourceRange outRange = {};
outRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
outRange.baseMipLevel = 0;
outRange.levelCount = 1;
outRange.baseArrayLayer = 0;
outRange.layerCount = metadata.eyes;
VkImageCopy copy = {};
copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.srcSubresource.baseArrayLayer = 1;
copy.srcSubresource.layerCount = 1;
copy.srcSubresource.mipLevel = 0;
VkImageSubresourceRange scratchRange = outRange;
scratchRange.layerCount = 1;
copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.dstSubresource.baseArrayLayer = 0;
copy.dstSubresource.layerCount = 1;
copy.dstSubresource.mipLevel = 0;
uf::renderer::Texture::setImageLayout( commandBuffer, outputAttachment.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, outRange );
uf::renderer::Texture::setImageLayout( commandBuffer, scratchAttachment.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, scratchRange );
copy.extent = { width, height, 1 };
VkImageCopy copy = {};
copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.srcSubresource.baseArrayLayer = 1;
copy.srcSubresource.layerCount = 1;
copy.srcSubresource.mipLevel = 0;
vkCmdCopyImage(
commandBuffer,
outputAttachment.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
scratchAttachment.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copy
);
copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.dstSubresource.baseArrayLayer = 0;
copy.dstSubresource.layerCount = 1;
copy.dstSubresource.mipLevel = 0;
uf::renderer::Texture::setImageLayout(
commandBuffer, scratchAttachment.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
scratchRange
);
copy.extent = { width, height, 1 };
vkCmdCopyImage( commandBuffer, outputAttachment.image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, scratchAttachment.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &copy );
uf::renderer::Texture::setImageLayout( commandBuffer, scratchAttachment.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, scratchRange );
}
}
#endif

View File

@ -213,7 +213,7 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
}
}
}
#if UF_USE_OPENVR
if ( ext::openvr::enabled && metadata.json["vr"].as<bool>() ) {
uf::stl::string vertexShaderFilename = uf::io::resolveURI(::fmt::format("{}/shaders/display/vr/{}.vert.spv", uf::io::root, metadata.json["stereo"].as<bool>(metadata.views == 2) ? "stereo" : "flat"));
uf::stl::string fragmentShaderFilename = uf::io::resolveURI(::fmt::format("{}/shaders/display/vr/{}.frag.spv", uf::io::root, metadata.json["stereo"].as<bool>(metadata.views == 2) ? "stereo" : "flat"));
@ -225,7 +225,18 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
auto& shader = blitter.material.getShader("fragment", "vr");
shader.aliasAttachment("color", this);
}
{
pod::Transform<> transform = {};
transform.position = {0, 0, -3};
transform.scale = { 1, -1, 1 };
transform.orientation = {0, 0, 0, 1};
metadata.camera.setTransform(transform);
metadata.camera.setProjection( ext::openvr::hmdProjectionMatrix(0, 0.001f, 0.0f), 0 );
metadata.camera.setProjection( ext::openvr::hmdProjectionMatrix(1, 0.001f, 0.0f), 1 );
}
}
#endif
}
this->build(true);
@ -284,6 +295,10 @@ void ext::vulkan::RenderTargetRenderMode::build( bool resized ) {
if ( ext::openvr::enabled && metadata.json["vr"].as<bool>() ) {
auto descriptor = blitter.descriptor;
descriptor.pipeline = "vr";
descriptor.renderMode = "VR";
descriptor.bind.point = VK_PIPELINE_BIND_POINT_GRAPHICS;
descriptor.depth.test = false;
descriptor.cullMode = uf::renderer::enums::CullMode::NONE;
blitter.update( descriptor );
}
}
@ -304,6 +319,14 @@ void ext::vulkan::RenderTargetRenderMode::tick() {
if ( rebuild && blitter.process ) {
this->build( resized );
}
if ( ext::openvr::enabled && metadata.json["vr"].as<bool>() ) {
auto& shader = blitter.material.getShader("vertex", "vr");
metadata.camera.update();
if ( shader.hasUniform("UBO") ) {
shader.updateBuffer( (const void*) &metadata.camera.data().viewport, sizeof(pod::Camera::Viewports), shader.getUniformBuffer("UBO") );
}
}
}
void ext::vulkan::RenderTargetRenderMode::destroy() {
ext::vulkan::RenderMode::destroy();
@ -312,20 +335,9 @@ void ext::vulkan::RenderTargetRenderMode::destroy() {
void ext::vulkan::RenderTargetRenderMode::render() {
if ( this->commands.container().empty() ) return;
auto& commands = getCommands( this->mostRecentCommandPoolId );
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_BEGIN, VkCommandBuffer{}, 0, {} );
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = NULL;
submitInfo.pWaitSemaphores = NULL;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pSignalSemaphores = NULL;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
submitInfo.commandBufferCount = 1;
VkSubmitInfo submitInfo = this->queue();
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, /*VK_NULL_HANDLE*/fences[states::currentBuffer]);
VK_CHECK_QUEUE_CHECKPOINT( queue, res );
@ -333,9 +345,6 @@ void ext::vulkan::RenderTargetRenderMode::render() {
this->executed = true;
}
void ext::vulkan::RenderTargetRenderMode::pipelineBarrier( VkCommandBuffer commandBuffer, uint8_t state ) {
ext::vulkan::RenderMode::pipelineBarrier( commandBuffer, state );
}
void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics ) {
// destroy if exists
uint32_t width = this->width > 0 ? this->width : (ext::vulkan::settings::width * this->scale);
@ -461,12 +470,27 @@ void ext::vulkan::RenderTargetRenderMode::createCommandBuffers( const uf::stl::v
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "renderPass[end]" );
vkCmdEndRenderPass(commandBuffer);
}
// post-renderpass commands
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
} );
#if 0 && UF_USE_OPENVR
if ( ext::vulkan::hasRenderMode("VR") ) {
// transition outputs
auto& outputAttachment = this->getAttachment("color");
VkImageSubresourceRange range = {};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
uf::renderer::Texture::setImageLayout( commandBuffer, outputAttachment.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, range );
}
#endif
}
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));

View File

@ -1,3 +1,5 @@
#include <uf/utils/memory/unordered_set.h>
namespace {
void transitionAttachmentsTo(
ext::vulkan::RenderMode* self,
@ -5,6 +7,8 @@ namespace {
VkCommandBuffer commandBuffer,
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
) {
uf::stl::unordered_set<VkImage> transitioned;
VkImageSubresourceRange subresourceRange;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
@ -35,6 +39,10 @@ namespace {
}
}
if ( image == VK_NULL_HANDLE ) continue;
if ( transitioned.count(image) > 0 ) continue;
transitioned.insert(image);
bool isDepth = descriptor.name.starts_with("depth");
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
@ -57,6 +65,8 @@ namespace {
VkCommandBuffer commandBuffer,
VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
) {
uf::stl::unordered_set<VkImage> transitioned;
VkImageSubresourceRange subresourceRange;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;
@ -87,6 +97,10 @@ namespace {
}
}
if ( image == VK_NULL_HANDLE ) continue;
if ( transitioned.count(image) > 0 ) continue;
transitioned.insert(image);
bool isDepth = descriptor.name.starts_with("depth");
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = 1;

View File

@ -13,10 +13,6 @@
#include <uf/utils/io/fmt.h>
#include <uf/ext/openvr/openvr.h>
namespace {
uf::Camera camera;
}
const uf::stl::string ext::vulkan::VrRenderMode::getType() const {
return "VR";
}
@ -25,7 +21,7 @@ void ext::vulkan::VrRenderMode::initialize(Device& device) {
uint32_t width = this->width > 0 ? this->width : (ext::vulkan::settings::width * this->scale);
uint32_t height = this->height > 0 ? this->height : (ext::vulkan::settings::height * this->scale);
metadata.pipeline = "vr";
metadata.pipeline = "vr";
ext::vulkan::RenderMode::initialize( device );
renderTarget.device = &device;
@ -160,8 +156,20 @@ void ext::vulkan::VrRenderMode::createCommandBuffers(const uf::stl::vector<ext::
RenderTargetRenderMode* layer = (RenderTargetRenderMode*) _;
auto& blitter = layer->blitter;
if ( !blitter.initialized || !blitter.process ) continue;
UF_MSG_DEBUG("currentPass={}, frame={}, renderMode name={}, type={}", currentPass, frame, layer->getName(), layer->getType());
ext::vulkan::GraphicDescriptor descriptor = bindGraphicDescriptor(blitter.descriptor);
ext::vulkan::GraphicDescriptor descriptor = blitter.descriptor;
descriptor.pipeline = "vr";
descriptor.renderMode = this->getName();
descriptor.bind.width = width;
descriptor.bind.height = height;
descriptor.bind.depth = 1;
descriptor.bind.point = VK_PIPELINE_BIND_POINT_GRAPHICS;
descriptor.subpass = 0;
descriptor.depth.test = false;
descriptor.inputs.vertex.count = 6;
descriptor.cullMode = uf::renderer::enums::CullMode::NONE;
// to-do: transition attachment here
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("blitter[{}: {}]", layer->getName(), layer->getType()) );
blitter.record(commandBuffer, descriptor, currentPass, currentDraw++, frame);
}
@ -175,6 +183,22 @@ void ext::vulkan::VrRenderMode::createCommandBuffers(const uf::stl::vector<ext::
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_END, commandBuffer, frame, {
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[end]" );
} );
// transition attachments
{
auto& leftEyeAttachment = this->getAttachment("left");
auto& rightEyeAttachment = this->getAttachment("right");
VkImageSubresourceRange range = {};
range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
uf::renderer::Texture::setImageLayout( commandBuffer, leftEyeAttachment.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, range );
uf::renderer::Texture::setImageLayout( commandBuffer, rightEyeAttachment.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, range );
}
}
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
@ -211,9 +235,6 @@ void ext::vulkan::VrRenderMode::tick() {
if ( rebuild && blitter.process ) {
this->build( resized );
}
::camera.update();
this->updateBuffer( (const void*) &::camera.data().viewport, sizeof(pod::Camera::Viewports), metadata.buffers["camera"] );
}
void ext::vulkan::VrRenderMode::destroy() {
@ -227,15 +248,7 @@ void ext::vulkan::VrRenderMode::render() {
VK_COMMAND_BUFFER_CALLBACK( EXECUTE_BEGIN, VkCommandBuffer{}, 0, {} );
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pWaitDstStageMask = NULL;
submitInfo.pWaitSemaphores = NULL;
submitInfo.waitSemaphoreCount = 0;
submitInfo.pSignalSemaphores = NULL;
submitInfo.signalSemaphoreCount = 0;
submitInfo.pCommandBuffers = &commands[states::currentBuffer];
submitInfo.commandBufferCount = 1;
VkSubmitInfo submitInfo = this->queue();
VkQueue queue = device->getQueue( QueueEnum::GRAPHICS );
VkResult res = vkQueueSubmit( queue, 1, &submitInfo, /*VK_NULL_HANDLE*/fences[states::currentBuffer]);

View File

@ -597,7 +597,6 @@ void ext::vulkan::render() {
uf::stl::vector<VkSubmitInfo> submitsCompute; submitsCompute.reserve( auxRenderModes.size() );
// stuff we can batch
// auto tasks = uf::thread::schedule( settings::invariant::multithreadedRecording );
for ( auto renderMode : auxRenderModes ) {
auto submitInfo = renderMode->queue();
if ( submitInfo.sType != VK_STRUCTURE_TYPE_SUBMIT_INFO ) continue;
@ -605,17 +604,12 @@ void ext::vulkan::render() {
else submitsGraphics.emplace_back(submitInfo);
renderMode->executed = true;
// tasks.queue([renderMode]{
ext::vulkan::setCurrentRenderMode(renderMode);
if ( renderMode->getType() != "Swapchain" ) {
uf::scene::render();
}
ext::vulkan::setCurrentRenderMode(NULL);
// });
ext::vulkan::setCurrentRenderMode(renderMode);
if ( renderMode->getType() != "Swapchain" ) {
uf::scene::render();
}
ext::vulkan::setCurrentRenderMode(NULL);
}
// uf::thread::execute( tasks );
// ext::vulkan::flushCommandBuffers();
VK_CHECK_RESULT(vkWaitForFences(device, fences.size(), fences.data(), VK_TRUE, VK_DEFAULT_FENCE_TIMEOUT));
VK_CHECK_RESULT(vkResetFences(device, fences.size(), fences.data()));
@ -646,7 +640,9 @@ void ext::vulkan::render() {
}
} else {
for ( auto& renderMode : renderModes ) {
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) continue;
if ( !renderMode || !renderMode->execute || !renderMode->metadata.limiter.execute ) {
continue;
}
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
if ( renderMode->getType() == "Swapchain" && settings::pipelines::fsr && ext::fsr::initialized ) {
@ -655,6 +651,7 @@ void ext::vulkan::render() {
}
#endif
ext::vulkan::setCurrentRenderMode(renderMode);
if ( renderMode->getType() != "Swapchain" ) {
uf::scene::render();
@ -665,6 +662,11 @@ void ext::vulkan::render() {
}
}
#if UF_USE_OPENVR
if ( ext::openvr::enabled ) {
ext::openvr::submit();
}
#endif
if ( ext::vulkan::settings::invariant::waitOnRenderEnd ) synchronize();
// if ( ext::openvr::context ) ext::openvr::postSubmit();