repaired VR support (to-do: make the VR rendermode work)

This commit is contained in:
ecker 2026-06-22 22:04:18 -05:00
parent e0fbed4a14
commit a98298b668
21 changed files with 1099 additions and 831 deletions

View File

@ -116,7 +116,7 @@
"deferred": true,
"gui": true,
"vsync": true, // vsync on vulkan side rather than engine-side
"hdr": true,
"hdr": false,
"vxgi": false, // to-do: fix issues
"culling": false,
"bloom": true,
@ -324,7 +324,7 @@
"preset": "native" // native (1x), quality (1.5x), balanced (1.7x), performance (2.0x), ultra (3.0x)
},
"vr" : {
"enable" : false,
"enable" : true,
"manifest": "./data/openvr_manifest.json",
"swap eyes": false,
"dominant eye": 0,
@ -357,7 +357,7 @@
"max": 0.1 // 0.2
},
"debug draw": {
"static": false,
"static": true,
"dynamic": true,
"trigger": false,
"contacts": false,

View File

@ -0,0 +1,27 @@
#version 450
#pragma shader_stage(fragment)
#extension GL_EXT_samplerless_texture_functions : require
layout (location = 0) in vec2 inUv;
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(constant_id = 0) const int FORCE_OPAQUE = 0;
#define TEXTURES 1
#include "../../common/macros.h"
#include "../../common/structs.h"
#include "../../common/functions.h"
void main() {
vec4 outColor = texture( samplerColor, inUv );
if ( FORCE_OPAQUE == 1 ) outColor.a = 1;
if ( inPass == 0 ) outLeft = outColor;
else if ( inPass == 1 ) outRight = outColor;
}

View File

@ -0,0 +1,23 @@
#version 450
#pragma shader_stage(vertex)
#include "../../common/macros.h"
#include "../../common/structs.h"
layout (location = 0) out vec2 outUv;
layout (location = 1) out flat uint outPass;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
} PushConstant;
layout (binding = 0) uniform Camera {
Viewport viewport[6];
} camera;
void main() {
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
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);
}

View File

@ -0,0 +1,27 @@
#version 450
#pragma shader_stage(fragment)
#extension GL_EXT_samplerless_texture_functions : require
layout (location = 0) in vec2 inUv;
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(constant_id = 0) const int FORCE_OPAQUE = 0;
#define TEXTURES 1
#include "../../common/macros.h"
#include "../../common/structs.h"
#include "../../common/functions.h"
void main() {
vec4 outColor = texture( samplerColor, vec3(inUv, inPass) );
if ( FORCE_OPAQUE == 1 ) outColor.a = 1;
if ( inPass == 0 ) outLeft = outColor;
else if ( inPass == 1 ) outRight = outColor;
}

View File

@ -0,0 +1,16 @@
#version 450
#pragma shader_stage(vertex)
layout (location = 0) out vec2 outUv;
layout (location = 1) out flat uint outPass;
layout( push_constant ) uniform PushBlock {
uint pass;
uint draw;
} PushConstant;
void main() {
outUv = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
outPass = PushConstant.pass;
gl_Position = vec4(outUv * 2.0f + -1.0f, 0.0f, 1.0f);
}

View File

@ -11,6 +11,8 @@
#include <uf/utils/renderer/renderer.h>
#include <uf/utils/window/payloads.h>
#include <uf/ext/openvr/openvr.h> // yuck
bool client::ready = false;
bool client::terminated = false;
uf::Window client::window;
@ -110,6 +112,9 @@ void client::initialize() {
#else
auto& configRenderJson = client::config["engine"]["ext"]["software"];
#endif
#if UF_USE_OPENVR
if ( ext::openvr::enabled ) return;
#endif
if ( !ext::json::isArray( configRenderJson["framebuffer"]["size"] ) ) {
uf::renderer::settings::width = payload.window.size.x;

View File

@ -24,27 +24,13 @@ namespace vr {
namespace ext {
namespace openvr {
struct Driver {
uf::stl::string name;
uf::stl::string serial;
uf::stl::string manifest;
vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount];
uf::stl::string types[vr::k_unMaxTrackedDeviceCount];
vr::IVRRenderModels* renderModels;
};
extern UF_API Driver driver;
extern UF_API vr::IVRSystem* context;
extern UF_API uint8_t renderPass;
extern UF_API float width, height;
extern UF_API bool enabled;
extern UF_API bool swapEyes;
extern UF_API uint8_t dominantEye;
bool UF_API initialize( int stage = 0 );
bool UF_API initialize();
void UF_API tick();
void UF_API terminate();
void UF_API submit();
void UF_API synchronize( bool async = true );
void UF_API synchronize();
float UF_API predictedTimeToDisplay( float additional = 1 );
float UF_API updateTracking( float additional = 1 );
void UF_API recommendedResolution( uint32_t& width, uint32_t& height );
@ -71,8 +57,10 @@ namespace ext {
bool UF_API controllerActive( vr::Controller_Hand );
bool UF_API requestRenderModel( const uf::stl::string& );
uf::Graphic& UF_API getRenderModel( const uf::stl::string& );
uf::Graphic& UF_API controllerRenderModel( vr::Controller_Hand );
uf::Mesh& UF_API getRenderModel( const uf::stl::string& );
uf::Mesh& UF_API controllerRenderModel( vr::Controller_Hand );
uf::Image& UF_API getRenderTexture( const uf::stl::string& );
uf::Image& UF_API controllerRenderTexture( vr::Controller_Hand );
void UF_API resetPosition();
/*

View File

@ -0,0 +1,18 @@
#pragma once
#include <uf/ext/vulkan/rendermode.h>
namespace ext {
namespace vulkan {
struct UF_API VrRenderMode : public ext::vulkan::RenderMode {
virtual const uf::stl::string getType() const;
virtual void createCommandBuffers( const uf::stl::vector<ext::vulkan::Graphic*>& graphics );
virtual void initialize( Device& device );
virtual void build( bool = true );
virtual void tick();
virtual void destroy();
virtual void render();
};
}
}

View File

@ -18,6 +18,7 @@ namespace ext {
uint32_t width = 0;
uint32_t height = 0;
uint8_t layers = 0;
} descriptor;
VkImage image;

View File

@ -486,27 +486,27 @@ pod::Matrix4t<T> /*UF_API*/ uf::matrix::orthographic( T l, T r, T b, T t ) {
}
template<typename T>
pod::Matrix4t<T> /*UF_API*/ uf::matrix::perspective( T fov, T raidou, T znear, T zfar ) {
pod::Matrix4t<T> m = uf::matrix::identity<T>();
pod::Matrix4t<T> m = uf::matrix::identity<T>();
T f = static_cast<T>(1) / tan(static_cast<T>(0.5) * fov);
m(0,0) = f / raidou;
m(1,1) = f;
m(0,0) = f / raidou;
m(1,1) = f;
#if UF_USE_VULKAN
m(1,1) = -f;
m(1,1) = -f;
#endif
m(3,2) = 1;
m(3,3) = 0;
m(3,2) = 1;
m(3,3) = 0;
if ( zfar <= 0 ) {
m(2,2) = 0;
m(2,3) = znear;
} else {
T range = zfar - znear;
m(2,2) = zfar / range;
m(2,3) = -(zfar * znear) / range;
}
if ( zfar <= 0 ) {
m(2,2) = 0;
m(2,3) = znear;
} else {
T range = zfar - znear;
m(2,2) = zfar / range;
m(2,3) = -(zfar * znear) / range;
}
return m;
return m;
}
template<typename T> T& uf::matrix::copy( T& destination, const T& source ) {
FOR_EACH(T::rows * T::columns, {

View File

@ -48,6 +48,10 @@
#include <uf/ext/vall_e/vall_e.h>
#include <uf/ext/valve/vpk.h>
#if UF_USE_OPENVR
#include <uf/ext/vulkan/rendermodes/vr.h>
#endif
bool uf::ready = false;
uf::stl::vector<uf::stl::string> uf::arguments;
uf::Serializer uf::config;
@ -112,15 +116,47 @@ void UF_API uf::load() {
uf::config.readFromFile(uf::io::root+"config.json");
}
void UF_API uf::load( ext::json::Value& json ) {
auto& configWindowJson = json["window"];
auto& configEngineJson = json["engine"];
auto& configEngineExtJson = configEngineJson["ext"];
auto& configEngineSceneJson = configEngineJson["scenes"];
auto& configEngineGraphJson = configEngineJson["graph"];
auto& configEngineDebugJson = configEngineJson["debug"];
auto& configEngineAudioJson = configEngineJson["audio"];
auto& configEngineLimitersJson = configEngineJson["limiters"];
auto& configEngineThreadJson = configEngineJson["threads"];
auto& configEnginePhysicsJson = configEngineJson["physics"];
auto& configEnginePhysicsSolverJson = configEnginePhysicsJson["solvers"];
auto& configEnginePhysicsCorrectionJson = configEnginePhysicsJson["correction"];
auto& configEnginePhysicsDebugDrawJson = configEnginePhysicsJson["debug draw"];
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
auto& configEngineExtFfxJson = configEngineExtJson["fsr"];
#endif
#if UF_USE_VALL_E
auto& configEngineExtValleJson = configEngineExtJson["vall_e"];
#endif
#if UF_USE_ULTRALIGHT
auto& configEngineExtUltralightJson = configEngineExtJson["ultralight"];
#endif
#if UF_USE_VULKAN
auto& configRenderJson = configEngineExtJson["vulkan"];
#elif UF_USE_OPENGL
auto& configRenderJson = configEngineExtJson["opengl"];
#else
auto& configRenderJson = configEngineExtJson["software"];
#endif
auto& configRenderInvariantJson = configRenderJson["invariant"];
auto& configRenderExperimentalJson = configRenderJson["experimental"];
auto& configRenderPipelinesJson = configRenderJson["pipelines"];
// Scene settings
{
auto& configEngineSceneJson = json["engine"]["scenes"];
uf::matrix::reverseInfiniteProjection = configEngineSceneJson["matrix"]["reverseInfinite"].as( uf::matrix::reverseInfiniteProjection );
}
// Graph settings
{
auto& configEngineGraphJson = json["engine"]["graph"];
uf::graph::initialBufferElements = configEngineGraphJson["initial buffer elements"].as(uf::graph::initialBufferElements);
if ( configEngineGraphJson["storage mode"].is<uf::stl::string>() ) {
auto mode = uf::string::lowercase( configEngineGraphJson["storage mode"].as<uf::stl::string>() );
@ -135,15 +171,14 @@ void UF_API uf::load( ext::json::Value& json ) {
// Various debug settings
{
auto& configEngineDebugJson = json["engine"]["debug"];
/*global*/::config.engine.gc.enabled = configEngineDebugJson["garbage collection"]["enabled"].as(/*global*/::config.engine.gc.enabled);
/*global*/::config.engine.gc.every = configEngineDebugJson["garbage collection"]["every"].as(/*global*/::config.engine.gc.every);
/*global*/::config.engine.gc.mode = configEngineDebugJson["garbage collection"]["mode"].as(/*global*/::config.engine.gc.mode);
/*global*/::config.engine.gc.announce = configEngineDebugJson["garbage collection"]["announce"].as(/*global*/::config.engine.gc.announce);
::config.engine.gc.enabled = configEngineDebugJson["garbage collection"]["enabled"].as(::config.engine.gc.enabled);
::config.engine.gc.every = configEngineDebugJson["garbage collection"]["every"].as(::config.engine.gc.every);
::config.engine.gc.mode = configEngineDebugJson["garbage collection"]["mode"].as(::config.engine.gc.mode);
::config.engine.gc.announce = configEngineDebugJson["garbage collection"]["announce"].as(::config.engine.gc.announce);
/*global*/::config.engine.limiter.print = configEngineDebugJson["framerate"]["print"].as(/*global*/::config.engine.limiter.print);
/*global*/::config.engine.fps.print = configEngineDebugJson["framerate"]["print"].as(/*global*/::config.engine.fps.print);
/*global*/::config.engine.fps.every = configEngineDebugJson["framerate"]["every"].as(/*global*/::config.engine.fps.every);
::config.engine.limiter.print = configEngineDebugJson["framerate"]["print"].as(::config.engine.limiter.print);
::config.engine.fps.print = configEngineDebugJson["framerate"]["print"].as(::config.engine.fps.print);
::config.engine.fps.every = configEngineDebugJson["framerate"]["every"].as(::config.engine.fps.every);
uf::Entity::deleteChildrenOnDestroy = configEngineDebugJson["entity"]["delete children on destroy"].as( uf::Entity::deleteChildrenOnDestroy );
uf::Entity::deleteComponentsOnDestroy = configEngineDebugJson["entity"]["delete components on destroy"].as( uf::Entity::deleteComponentsOnDestroy );
@ -160,18 +195,17 @@ void UF_API uf::load( ext::json::Value& json ) {
}
// Limiter settings
{
auto& configEngineLimitersJson = json["engine"]["limiters"];
if ( configEngineLimitersJson["framerate"].as<uf::stl::string>() == "auto" && json["window"]["refresh rate"].is<size_t>() ) {
if ( configEngineLimitersJson["framerate"].as<uf::stl::string>() == "auto" && configWindowJson["refresh rate"].is<size_t>() ) {
float scale = 1.0;
size_t refreshRate = json["window"]["refresh rate"].as<size_t>();
size_t refreshRate = configWindowJson["refresh rate"].as<size_t>();
configEngineLimitersJson["framerate"] = refreshRate * scale;
UF_MSG_DEBUG("Setting framerate cap to {}", (int) refreshRate * scale);
}
/* Frame limiter */ {
size_t limit = configEngineLimitersJson["framerate"].as<size_t>();
/*global*/::times.limiter = limit != 0 ? 1.0 / limit : 0;
UF_MSG_DEBUG("Limiter set to {} ms", /*global*/::times.limiter);
::times.limiter = limit != 0 ? 1.0 / limit : 0;
UF_MSG_DEBUG("Limiter set to {} ms", ::times.limiter);
}
/* Max delta time */{
size_t limit = configEngineLimitersJson["deltaTime"].as<size_t>();
@ -181,10 +215,9 @@ void UF_API uf::load( ext::json::Value& json ) {
// Thread settings
{
auto& configEngineThreadJson = json["engine"]["threads"];
if ( configEngineThreadJson["frame limiter"].as<uf::stl::string>() == "auto" && json["window"]["refresh rate"].is<size_t>() ) {
if ( configEngineThreadJson["frame limiter"].as<uf::stl::string>() == "auto" && configWindowJson["refresh rate"].is<size_t>() ) {
float scale = 2.0;
size_t refreshRate = json["window"]["refresh rate"].as<size_t>();
size_t refreshRate = configWindowJson["refresh rate"].as<size_t>();
configEngineThreadJson["frame limiter"] = refreshRate * scale;
UF_MSG_DEBUG("Setting thread frame limiter to {}", (int) refreshRate * scale);
}
@ -209,14 +242,12 @@ void UF_API uf::load( ext::json::Value& json ) {
// Physics settings
{
auto& configEnginePhysicsJson = json["engine"]["physics"];
uf::physics::settings.async = configEnginePhysicsJson["async"].as(uf::physics::settings.async);
uf::physics::settings.timestep = configEnginePhysicsJson["timestep"].as(uf::physics::settings.timestep);
uf::physics::settings.fixedStep = configEnginePhysicsJson["fixed step"].as(uf::physics::settings.fixedStep);
uf::physics::settings.substeps = configEnginePhysicsJson["substeps"].as(uf::physics::settings.substeps);
uf::physics::settings.flattenTransforms = configEnginePhysicsJson["flatten transforms"].as(uf::physics::settings.flattenTransforms);
auto& configEnginePhysicsSolverJson = configEnginePhysicsJson["solvers"];
if ( ext::json::isObject( configEnginePhysicsSolverJson ) ) {
uf::physics::settings.useGjk = configEnginePhysicsSolverJson["gjk"].as(uf::physics::settings.useGjk);
uf::physics::settings.blockContactSolver = configEnginePhysicsSolverJson["block"].as(uf::physics::settings.blockContactSolver);
@ -224,14 +255,12 @@ void UF_API uf::load( ext::json::Value& json ) {
uf::physics::settings.resolveBlockContact = configEnginePhysicsSolverJson["resolve invalid"].as(uf::physics::settings.resolveBlockContact);
uf::physics::settings.solverIterations = configEnginePhysicsSolverJson["iterations"].as(uf::physics::settings.solverIterations);
}
auto& configEnginePhysicsCorrectionJson = configEnginePhysicsJson["correction"];
if ( ext::json::isObject( configEnginePhysicsCorrectionJson ) ) {
uf::physics::settings.ngsPositionSolver = configEnginePhysicsCorrectionJson["ngs"].as(uf::physics::settings.ngsPositionSolver);
uf::physics::settings.baumgarteCorrectionPercent = configEnginePhysicsCorrectionJson["percent"].as(uf::physics::settings.baumgarteCorrectionPercent);
uf::physics::settings.baumgarteCorrectionSlop = configEnginePhysicsCorrectionJson["slop"].as(uf::physics::settings.baumgarteCorrectionSlop);
uf::physics::settings.maxLinearCorrection = configEnginePhysicsCorrectionJson["max"].as(uf::physics::settings.maxLinearCorrection);
}
auto& configEnginePhysicsDebugDrawJson = configEnginePhysicsJson["debug draw"];
if ( ext::json::isObject( configEnginePhysicsDebugDrawJson ) ) {
if ( configEnginePhysicsDebugDrawJson["static"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_STATIC;
if ( configEnginePhysicsDebugDrawJson["dynamic"].as<bool>() ) uf::physics::settings.debugDraw.mask |= pod::Collider::CATEGORY_DYNAMIC;
@ -257,7 +286,6 @@ void UF_API uf::load( ext::json::Value& json ) {
// Audio settings
{
auto& configEngineAudioJson = json["engine"]["audio"];
uf::audio::muted = configEngineAudioJson["mute"].as( uf::audio::muted );
uf::audio::asyncUpdate = configEngineAudioJson["async update"].as( uf::audio::asyncUpdate );
uf::audio::streamsByDefault = configEngineAudioJson["streams by default"].as( uf::audio::streamsByDefault );
@ -278,23 +306,29 @@ void UF_API uf::load( ext::json::Value& json ) {
}
// Various external settings
#if UF_USE_DISCORD
{
/*global*/::config.engine.ext.discord.enabled = json["engine"]["ext"]["discord"]["enabled"].as(/*global*/::config.engine.ext.discord.enabled);
/*global*/::config.engine.ext.imgui.enabled = json["engine"]["ext"]["imgui"]["enabled"].as(/*global*/::config.engine.ext.imgui.enabled);
::config.engine.ext.discord.enabled = configEngineExtJson["discord"]["enabled"].as(::config.engine.ext.discord.enabled);
}
#endif
#if UF_USE_IMGUI
{
::config.engine.ext.imgui.enabled = configEngineExtJson["imgui"]["enabled"].as(::config.engine.ext.imgui.enabled);
}
#endif
#if UF_USE_VALL_E
// VALL-E settings
{
auto& configEngineExtValleJson = json["engine"]["ext"]["vall_e"];
/*global*/::config.engine.ext.vall_e.enabled = configEngineExtValleJson["enabled"].as(/*global*/::config.engine.ext.vall_e.enabled);
/*global*/::config.engine.ext.vall_e.model_path = configEngineExtValleJson["model_path"].as(/*global*/::config.engine.ext.vall_e.model_path);
/*global*/::config.engine.ext.vall_e.encodec_path = configEngineExtValleJson["encodec_path"].as(/*global*/::config.engine.ext.vall_e.encodec_path);
::config.engine.ext.vall_e.enabled = configEngineExtValleJson["enabled"].as(::config.engine.ext.vall_e.enabled);
::config.engine.ext.vall_e.model_path = configEngineExtValleJson["model_path"].as(::config.engine.ext.vall_e.model_path);
::config.engine.ext.vall_e.encodec_path = configEngineExtValleJson["encodec_path"].as(::config.engine.ext.vall_e.encodec_path);
}
#endif
#if UF_USE_ULTRALIGHT
// Ultralight settings (painfully unused)
{
auto& configEngineExtUltralightJson = json["engine"]["ext"]["ultralight"];
/*global*/::config.engine.ext.ultralight.enabled = configEngineExtUltralightJson["enabled"].as(/*global*/::config.engine.ext.ultralight.enabled);
::config.engine.ext.ultralight.enabled = configEngineExtUltralightJson["enabled"].as(::config.engine.ext.ultralight.enabled);
ext::ultralight::scale = configEngineExtUltralightJson["scale"].as( ext::ultralight::scale );
ext::ultralight::log = configEngineExtUltralightJson["log"].as( ext::ultralight::log );
}
@ -302,17 +336,6 @@ void UF_API uf::load( ext::json::Value& json ) {
// Renderer settings
{
#if UF_USE_VULKAN
auto& configRenderJson = json["engine"]["ext"]["vulkan"];
#elif UF_USE_OPENGL
auto& configRenderJson = json["engine"]["ext"]["opengl"];
#else
auto& configRenderJson = json["engine"]["ext"]["software"];
#endif
auto& configRenderInvariantJson = configRenderJson["invariant"];
auto& configRenderExperimentalJson = configRenderJson["experimental"];
auto& configRenderPipelinesJson = configRenderJson["pipelines"];
uf::renderer::settings::validation::messages = configRenderJson["validation"]["messages"].as( uf::renderer::settings::validation::messages );
uf::renderer::settings::validation::checkpoints = configRenderJson["validation"]["checkpoints"].as( uf::renderer::settings::validation::checkpoints );
@ -323,7 +346,7 @@ void UF_API uf::load( ext::json::Value& json ) {
uf::renderer::settings::defaultDeferBufferDestroy = configRenderInvariantJson["default defer buffer destroy"].as( uf::renderer::settings::defaultDeferBufferDestroy );
#if 0
uf::renderer::settings::defaultCommandBufferImmediate = true;
/*global*/::requestDeferredCommandBufferSubmit = !configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
::requestDeferredCommandBufferSubmit = !configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
#else
uf::renderer::settings::defaultCommandBufferImmediate = configRenderInvariantJson["default command buffer immediate"].as( uf::renderer::settings::defaultCommandBufferImmediate );
#endif
@ -331,7 +354,7 @@ void UF_API uf::load( ext::json::Value& json ) {
#endif
#if 1
uf::renderer::settings::experimental::dedicatedThread = false;
/*global*/::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
::requestDedicatedRenderThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
#else
uf::renderer::settings::experimental::dedicatedThread = configRenderExperimentalJson["dedicated thread"].as( uf::renderer::settings::experimental::dedicatedThread );
#endif
@ -340,40 +363,44 @@ void UF_API uf::load( ext::json::Value& json ) {
uf::renderer::settings::invariant::individualPipelines = configRenderInvariantJson["individual pipelines"].as( uf::renderer::settings::invariant::individualPipelines );
}
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
ext::fsr::preset = json["engine"]["ext"]["fsr"]["preset"].as(ext::fsr::preset);
ext::fsr::jitterScale = json["engine"]["ext"]["fsr"]["jitter scale"].as(ext::fsr::jitterScale);
ext::fsr::sharpness = json["engine"]["ext"]["fsr"]["sharpness"].as(ext::fsr::sharpness);
ext::fsr::preset = configEngineExtFfxJson["preset"].as(ext::fsr::preset);
ext::fsr::jitterScale = configEngineExtFfxJson["jitter scale"].as(ext::fsr::jitterScale);
ext::fsr::sharpness = configEngineExtFfxJson["sharpness"].as(ext::fsr::sharpness);
ext::fsr::frameUpscale = json["engine"]["ext"]["fsr"]["upscale"].as(ext::fsr::frameUpscale);
ext::fsr::frameInterpolation = json["engine"]["ext"]["fsr"]["interpolation"].as(ext::fsr::frameInterpolation);
ext::fsr::frameUpscale = configEngineExtFfxJson["upscale"].as(ext::fsr::frameUpscale);
ext::fsr::frameInterpolation = configEngineExtFfxJson["interpolation"].as(ext::fsr::frameInterpolation);
{
bool enabled = json["engine"]["ext"]["fsr"]["enabled"].as(true);
if ( !enabled ) {
ext::fsr::frameUpscale = false;
ext::fsr::frameInterpolation = false;
}
if ( !configEngineExtFfxJson["enabled"].as(true) ) {
ext::fsr::frameUpscale = false;
ext::fsr::frameInterpolation = false;
}
#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);
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
if ( uf::renderer::settings::pipelines::fsr ) {
float factor = 1.0f;
auto mode = uf::string::lowercase( ext::fsr::preset );
if ( mode == "native" ) renderMode.scale = 1;
else if ( mode == "quality" ) renderMode.scale = 1.0f / (1.5f);
else if ( mode == "balanced" ) renderMode.scale = 1.0f / (1.7f);
else if ( mode == "performance" ) renderMode.scale = 1.0f / (2.0f);
else if ( mode == "ultra" ) renderMode.scale = 1.0f / (3.0f);
if ( mode == "native" ) factor = 1.0f;
else if ( mode == "quality" ) factor = 1.5f;
else if ( mode == "balanced" ) factor = 1.7f;
else if ( mode == "performance" ) factor = 2.0f;
else if ( mode == "ultra" ) factor = 3.0f;
else {
renderMode.scale = 1;
UF_MSG_WARNING("Invalid FFX FSR preset enum string specified: {}", mode);
}
renderMode.scale = 1.0f / factor;
UF_MSG_DEBUG("Using FFX FSR Preset: {} ({:.3f}% render scale)", mode, (100.0f / renderMode.scale));
} else
#endif
renderMode.scale = uf::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as(1.0f);
renderMode.scale = configRenderJson["framebuffer"]["size"].as(1.0f);
UF_MSG_DEBUG("Geometry render scale: {:.3f}", renderMode.scale);
}
}
@ -434,11 +461,11 @@ void UF_API uf::initialize() {
std::srand(std::time(NULL));
}
/* Open output file */ {
/*global*/::io.filenames.output = uf::io::root+"/logs/output.txt";
/*global*/::io.output.open(/*global*/::io.filenames.output);
::io.filenames.output = uf::io::root+"/logs/output.txt";
::io.output.open(::io.filenames.output);
}
/* Initialize timers */ {
/*global*/::times.sys.start();
::times.sys.start();
}
/* Read persistent data */ {
// #include "./inits/persistence.inl"
@ -495,6 +522,7 @@ void UF_API uf::initialize() {
}
uf::allocator::override = configMemoryPoolJson["override"].as( uf::allocator::override );
}
/* Setup commands */ {
uf::console::initialize();
}
@ -507,10 +535,9 @@ void UF_API uf::initialize() {
}
/* Create initial scene (kludge) */ {
uf::Scene& scene = uf::instantiator::instantiate<uf::Scene>(); //new uf::Scene;
uf::Scene& scene = uf::instantiator::instantiate<uf::Scene>();
uf::scene::scenes.emplace_back(&scene);
auto& metadata = scene.getComponent<uf::Serializer>();
// metadata["system"]["config"] = uf::config;
}
uf::load( uf::config );
@ -539,7 +566,7 @@ void UF_API uf::initialize() {
} else if ( ext::json::isArray( configRenderJson["framebuffer"]["size"] ) ) {
uf::renderer::settings::width = configRenderJson["framebuffer"]["size"][0].as(uf::renderer::settings::width);
uf::renderer::settings::height = configRenderJson["framebuffer"]["size"][1].as(uf::renderer::settings::height);
uf::stl::string filter = uf::string::lowercase( configRenderJson["framebuffer"]["size"][2].as<uf::stl::string>() );
uf::stl::string filter = uf::string::lowercase( configRenderJson["framebuffer"]["size"][2].as<uf::stl::string>() );
if ( filter == "nearest" ) uf::renderer::settings::swapchainUpscaleFilter = uf::renderer::enums::Filter::NEAREST;
else if ( filter == "linear" ) uf::renderer::settings::swapchainUpscaleFilter = uf::renderer::enums::Filter::LINEAR;
@ -607,12 +634,9 @@ void UF_API uf::initialize() {
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
uf::renderer::settings::pipelines::fsr = configRenderPipelinesJson["fsr"].as( uf::renderer::settings::pipelines::fsr );
// ext::fsr::enabled = uf::renderer::settings::pipelines::fsr;
#endif
if ( uf::renderer::settings::pipelines::rt ) {
// uf::renderer::settings::pipelines::vxgi = false;
// uf::renderer::settings::pipelines::culling = false;
uf::config["engine"]["scenes"]["lights"]["shadows"]["enabled"] = false;
}
#define JSON_TO_FORMAT( key ) if ( configRenderJson["formats"][#key].is<uf::stl::string>() ) {\
@ -645,110 +669,13 @@ void UF_API uf::initialize() {
}
#endif
/* Physics */ {
// uf::physics::initialize();
}
#if UF_USE_OPENVR
{
auto& configVrJson = uf::config["engine"]["ext"]["vr"];
ext::openvr::enabled = configVrJson["enable"].as( ext::openvr::enabled );
ext::openvr::swapEyes = configVrJson["swap eyes"].as( ext::openvr::swapEyes );
if ( configVrJson["dominant eye"].is<int>() ) {
ext::openvr::dominantEye = configVrJson["dominant eye"].as<int>();
} else if ( configVrJson["dominant eye"].as<uf::stl::string>() == "left" ) ext::openvr::dominantEye = 0;
else if ( configVrJson["dominant eye"].as<uf::stl::string>() == "right" ) ext::openvr::dominantEye = 1;
ext::openvr::driver.manifest = configVrJson["manifest"].as(ext::openvr::driver.manifest);
if ( ext::openvr::enabled ) uf::config["engine"]["render modes"]["stereo deferred"] = true;
}
#endif
/* Initialize Vulkan */ {
// to-do: have this set per config value instead of relying on the scene to handle its own rendermodes
if ( false ) {
// setup render mode
if ( uf::config["engine"]["render modes"]["deferred"].as<bool>(true) ) {
auto* renderMode = new uf::renderer::DeferredRenderMode;
if ( uf::config["engine"]["ext"]["vulkan"]["pipelines"]["postProcess"].is<uf::stl::string>() )
renderMode->metadata.json["postProcess"] = uf::config["engine"]["ext"]["vulkan"]["pipelines"]["postProcess"];
renderMode->blitter.descriptor.renderMode = "Swapchain";
renderMode->blitter.descriptor.subpass = 0;
#if UF_USE_FFX_FSR || UF_USE_FFX_SDK
if ( uf::renderer::settings::pipelines::fsr ) {
auto mode = uf::string::lowercase( ext::fsr::preset );
if ( mode == "native" ) renderMode->scale = 1;
else if ( mode == "quality" ) renderMode->scale = 1.0f / (1.5f);
else if ( mode == "balanced" ) renderMode->scale = 1.0f / (1.7f);
else if ( mode == "performance" ) renderMode->scale = 1.0f / (2.0f);
else if ( mode == "ultra" ) renderMode->scale = 1.0f / (3.0f);
else {
renderMode->scale = 1;
UF_MSG_WARNING("Invalid FFX FSR preset enum string specified: {}", mode);
}
UF_MSG_DEBUG("Using FFX FSR Preset: {} ({:.3f}% render scale)", mode, (100.0f / renderMode->scale));
} else
#endif
renderMode->scale = uf::config["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as(1.0f);
UF_MSG_DEBUG("Geometry render scale: {:.3f}", renderMode->scale);
if ( uf::config["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
renderMode->metadata.eyes = 2;
}
#if UF_USE_VULKAN
if ( uf::renderer::settings::pipelines::deferred ) {
renderMode->metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::deferred);
}
if ( uf::renderer::settings::pipelines::culling ) {
renderMode->metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::culling);
}
if ( uf::renderer::settings::pipelines::rt ) {
renderMode->metadata.pipelines.emplace_back("skinning");
}
#endif
uf::renderer::addRenderMode( renderMode, "" );
}
if ( uf::config["engine"]["render modes"]["gui"].as<bool>(true) ) {
auto* renderMode = new uf::renderer::RenderTargetRenderMode;
if ( uf::config["engine"]["ext"]["vulkan"]["pipelines"]["postProcess"].is<uf::stl::string>() )
renderMode->metadata.json["postProcess"] = uf::config["engine"]["ext"]["vulkan"]["pipelines"]["postProcess"];
uf::stl::string name = "Gui";
renderMode->blitter.descriptor.renderMode = "Swapchain";
renderMode->blitter.descriptor.subpass = 0;
renderMode->metadata.type = "single";
uf::renderer::addRenderMode( renderMode, name );
}
}
}
#if UF_USE_OPENVR
if ( ext::openvr::enabled ) {
ext::openvr::initialize();
uint32_t width, height;
ext::openvr::recommendedResolution( width, height );
auto& renderMode = uf::renderer::getRenderMode("", true);
renderMode.width = width;
renderMode.height = height;
UF_MSG_DEBUG("Recommended VR Resolution: {}, {}", renderMode.width, renderMode.height);
if ( uf::config["engine"]["ext"]["vr"]["scale"].is<float>() ) {
float scale = uf::config["engine"]["ext"]["vr"]["scale"].as<float>();
renderMode.width *= scale;
renderMode.height *= scale;
UF_MSG_DEBUG("VR Resolution: {}, {}", renderMode.width, renderMode.height);
if ( ext::openvr::enabled && (ext::openvr::enabled = ext::openvr::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);
}
}
#endif
@ -770,23 +697,23 @@ void UF_API uf::initialize() {
}
#endif
#if UF_USE_DISCORD
/* Discord */ if ( /*global*/::config.engine.ext.discord.enabled ) {
/* Discord */ if ( ::config.engine.ext.discord.enabled ) {
ext::discord::initialize();
}
#endif
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( /*global*/::config.engine.ext.ultralight.enabled ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::initialize();
}
#endif
#if UF_USE_IMGUI
if ( /*global*/::config.engine.ext.imgui.enabled ) {
if ( ::config.engine.ext.imgui.enabled ) {
// ext::imgui::initialize();
}
#endif
#if 0 && UF_USE_VALL_E
if ( /*global*/::config.engine.ext.vall_e.enabled ) {
ext::vall_e::initialize( /*global*/::config.engine.ext.vall_e.model_path, /*global*/::config.engine.ext.vall_e.encodec_path );
if ( ::config.engine.ext.vall_e.enabled ) {
ext::vall_e::initialize( ::config.engine.ext.vall_e.model_path, ::config.engine.ext.vall_e.encodec_path );
// bind the hook
uf::hooks.addHook( "llm:VALL-E.synthesize", [&](ext::json::Value& json){
@ -811,8 +738,8 @@ void UF_API uf::initialize() {
#endif
/* Add hooks */ {
uf::hooks.addHook( "game:Scene.Load", [&](ext::json::Value& json){
/*global*/::sceneTransition.payload = json;
/*global*/::sceneTransition.phase = 0;
::sceneTransition.payload = json;
::sceneTransition.phase = 0;
});
uf::hooks.addHook( "system:Quit", [&](ext::json::Value& json){
if ( json["message"].is<uf::stl::string>() ) {
@ -825,12 +752,12 @@ void UF_API uf::initialize() {
/* Initialize root scene*/ {
ext::json::Value payload;
payload["scene"] = uf::config["engine"]["scenes"]["start"];
/*global*/::sceneTransition.payload = payload;
/*global*/::sceneTransition.phase = 0;
::sceneTransition.payload = payload;
::sceneTransition.phase = 0;
}
uf::ready = true;
UF_MSG_INFO("EXT took {} seconds to initialize", /*global*/::times.sys.elapsed().asDouble());
UF_MSG_INFO("EXT took {} seconds to initialize", ::times.sys.elapsed().asDouble());
}
void UF_API uf::tick() {
@ -843,9 +770,9 @@ void UF_API uf::tick() {
#if 1
// skip the next tick to load the next scene to ensure nothing's happening
if ( /*global*/::sceneTransition.phase >= 0 ) {
auto target = /*global*/::sceneTransition.payload["scene"].as<uf::stl::string>();
auto& phase = /*global*/::sceneTransition.phase;
if ( ::sceneTransition.phase >= 0 ) {
auto target = ::sceneTransition.payload["scene"].as<uf::stl::string>();
auto& phase = ::sceneTransition.phase;
++phase;
@ -856,12 +783,12 @@ void UF_API uf::tick() {
uf::renderer::synchronize();
if ( uf::renderer::settings::experimental::dedicatedThread ) {
/*global*/::requestDedicatedRenderThread = true;
::requestDedicatedRenderThread = true;
uf::renderer::settings::experimental::dedicatedThread = !uf::renderer::settings::experimental::dedicatedThread;
}
#if UF_USE_VULKAN
if ( !uf::renderer::settings::defaultCommandBufferImmediate ) {
/*global*/::requestDeferredCommandBufferSubmit = true;
::requestDeferredCommandBufferSubmit = true;
uf::renderer::settings::defaultCommandBufferImmediate = !uf::renderer::settings::defaultCommandBufferImmediate;
}
#endif
@ -869,7 +796,7 @@ void UF_API uf::tick() {
uf::scene::unloadScene();
uf::scene::loadScene( target );
/*global*/::sceneTransition.phase = -1;
::sceneTransition.phase = -1;
#if UF_USE_VULKAN
uf::renderer::flushCommandBuffers();
@ -884,7 +811,7 @@ void UF_API uf::tick() {
spec::controller::tick();
}
#if UF_USE_OPENVR
/* OpenVR */ if ( ext::openvr::context ) {
/* OpenVR */ if ( ext::openvr::enabled ) {
ext::openvr::tick();
}
#endif
@ -944,7 +871,7 @@ void UF_API uf::tick() {
uf::thread::process( threadMain );
}
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( /*global*/::config.engine.ext.ultralight.enabled ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::tick();
}
#endif
@ -953,22 +880,22 @@ void UF_API uf::tick() {
}
#if UF_USE_DISCORD
/* Discord */ if ( /*global*/::config.engine.ext.discord.enabled ) {
/* Discord */ if ( ::config.engine.ext.discord.enabled ) {
ext::discord::tick();
}
#endif
#if UF_USE_IMGUI
if ( /*global*/::config.engine.ext.imgui.enabled ) {
if ( ::config.engine.ext.imgui.enabled ) {
ext::imgui::tick();
}
#endif
// perform GC on entities
if ( /*global*/::config.engine.gc.enabled ) {
TIMER( /*global*/::config.engine.gc.every ) {
size_t collected = uf::instantiator::collect( /*global*/::config.engine.gc.mode );
if ( ::config.engine.gc.enabled ) {
TIMER( ::config.engine.gc.every ) {
size_t collected = uf::instantiator::collect( ::config.engine.gc.mode );
if ( collected > 0 ) {
if ( /*global*/::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected {} unused entities", (int) collected);
if ( ::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected {} unused entities", (int) collected);
}
}
}
@ -978,10 +905,10 @@ void UF_API uf::tick() {
#endif
#if !UF_ENV_DREAMCAST
if ( /*global*/::times.limiter > 0 ) {
if ( ::times.limiter > 0 ) {
static auto nextFrameTime = std::chrono::steady_clock::now();
double limiterMs = /*global*/::times.limiter * 1000.0;
double limiterMs = ::times.limiter * 1000.0;
auto limiterDuration = std::chrono::duration_cast<std::chrono::steady_clock::duration>(std::chrono::duration<double, std::milli>(limiterMs));
nextFrameTime += limiterDuration;
@ -996,14 +923,14 @@ void UF_API uf::tick() {
}
auto& controller = uf::scene::getCurrentScene().getController();
if ( /*global*/::requestDedicatedRenderThread && controller.getName() == "Player" ) {
/*global*/::requestDedicatedRenderThread = false;
if ( ::requestDedicatedRenderThread && controller.getName() == "Player" ) {
::requestDedicatedRenderThread = false;
uf::renderer::settings::experimental::dedicatedThread = true;
UF_MSG_DEBUG("Dedicated render requested");
}
#if UF_USE_VULKAN
if ( /*global*/::requestDeferredCommandBufferSubmit && controller.getName() == "Player" ) {
/*global*/::requestDeferredCommandBufferSubmit = false;
if ( ::requestDeferredCommandBufferSubmit && controller.getName() == "Player" ) {
::requestDeferredCommandBufferSubmit = false;
uf::renderer::settings::defaultCommandBufferImmediate = false;
UF_MSG_DEBUG("Defer command buffer submit requested");
}
@ -1022,11 +949,11 @@ void UF_API uf::tick() {
threadMain.metrics.totalFrameTimeMs.store(frameTime.count(), std::memory_order_relaxed);
#endif
/* FPS Print */ if ( /*global*/::config.engine.fps.print ) {
++/*global*/::times.frames;
++/*global*/::times.total.frames;
TIMER( /*global*/::config.engine.fps.every ) {
UF_MSG_DEBUG("System: {:.3f} ms/frame | Time: {:.3f} | Frames: {} | FPS: {:.3f}", (time * 1000.0 / /*global*/::times.frames), time, /*global*/::times.frames, /*global*/::times.frames / time);
/* FPS Print */ if ( ::config.engine.fps.print ) {
++::times.frames;
++::times.total.frames;
TIMER( ::config.engine.fps.every ) {
UF_MSG_DEBUG("System: {:.3f} ms/frame | Time: {:.3f} | Frames: {} | FPS: {:.3f}", (time * 1000.0 / ::times.frames), time, ::times.frames, ::times.frames / time);
#if UF_ENV_DREAMCAST
DC_STATS();
#endif
@ -1035,25 +962,25 @@ void UF_API uf::tick() {
for ( auto& [ name, stats ] : metrics ) UF_MSG_DEBUG("Thread {}: active={}, idle={}, total={}, tasks={}", name, std::get<0>(stats), std::get<1>(stats), std::get<2>(stats), std::get<3>(stats) );
#endif
/*global*/::times.frames = 0;
::times.frames = 0;
}
}
}
void UF_API uf::render() {
if ( uf::scene::scenes.empty() ) return;
if ( /*global*/::sceneTransition.phase >= 0 ) {
if ( ::sceneTransition.phase >= 0 ) {
return;
}
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( /*global*/::config.engine.ext.ultralight.enabled ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::render();
}
#endif
#if UF_USE_OPENVR
if ( ext::openvr::context ) {
vr::VRCompositor()->SubmitExplicitTimingData();
{
ext::openvr::synchronize();
}
#endif
/* Render scene */ {
@ -1061,8 +988,7 @@ void UF_API uf::render() {
uf::renderer::render();
}
#if UF_USE_OPENVR
if ( ext::openvr::context ) {
ext::openvr::synchronize();
if ( !uf::renderer::hasRenderMode("VR") ) {
ext::openvr::submit();
}
#endif
@ -1075,22 +1001,22 @@ void UF_API uf::terminate() {
spec::controller::terminate();
}
#if UF_USE_VALL_E
if ( /*global*/::config.engine.ext.vall_e.enabled ) {
if ( ::config.engine.ext.vall_e.enabled ) {
ext::vall_e::terminate();
}
#endif
#if UF_USE_IMGUI
if ( /*global*/::config.engine.ext.imgui.enabled ) {
if ( ::config.engine.ext.imgui.enabled ) {
ext::imgui::terminate();
}
#endif
#if UF_USE_ULTRALIGHT
/* Ultralight-UX */ if ( /*global*/::config.engine.ext.ultralight.enabled ) {
/* Ultralight-UX */ if ( ::config.engine.ext.ultralight.enabled ) {
ext::ultralight::terminate();
}
#endif
#if UF_USE_OPENVR
/* OpenVR */ if ( ext::openvr::context ) {
/* OpenVR */ if ( ext::openvr::enabled ) {
ext::openvr::terminate();
}
#endif
@ -1113,10 +1039,10 @@ void UF_API uf::terminate() {
{
uf::scene::destroy();
}
/* Garbage collection */ if ( /*global*/::config.engine.gc.enabled ) {
size_t collected = uf::instantiator::collect( /*global*/::config.engine.gc.mode );
/* Garbage collection */ if ( ::config.engine.gc.enabled ) {
size_t collected = uf::instantiator::collect( ::config.engine.gc.mode );
if ( collected > 0 ) {
if ( /*global*/::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected {} unused entities", (int) collected);
if ( ::config.engine.gc.announce ) UF_MSG_DEBUG("GC collected {} unused entities", (int) collected);
}
}
@ -1144,14 +1070,14 @@ void UF_API uf::terminate() {
}
/* Print system stats */ {
/*global*/::times.total.time = /*global*/::times.sys.elapsed().asDouble();
UF_MSG_DEBUG("System: Total Time: {} | Total Frames: {} | Average FPS: {}", /*global*/::times.total.time, /*global*/::times.total.frames, /*global*/::times.total.frames / /*global*/::times.total.time);
::times.total.time = ::times.sys.elapsed().asDouble();
UF_MSG_DEBUG("System: Total Time: {} | Total Frames: {} | Average FPS: {}", ::times.total.time, ::times.total.frames, ::times.total.frames / ::times.total.time);
}
/* Flush input buffer */ {
/*global*/::io.output << /*global*/::io.input << "\n";
for ( const auto& str : uf::iostream.getHistory() ) /*global*/::io.output << str << "\n";
/*global*/::io.output << "\nTerminated after " << /*global*/::times.sys.elapsed().asDouble() << " seconds" << "\n";
/*global*/::io.output.close();
::io.output << ::io.input << "\n";
for ( const auto& str : uf::iostream.getHistory() ) ::io.output << str << "\n";
::io.output << "\nTerminated after " << ::times.sys.elapsed().asDouble() << " seconds" << "\n";
::io.output.close();
}
}

View File

@ -52,6 +52,7 @@ void ext::GuiManagerBehavior::tick( uf::Object& self ) {
renderMode.blitter.descriptor.subpass = 0;
renderMode.metadata.type = "single";
renderMode.metadata.name = name;
renderMode.metadata.json["vr"] = true;
if ( uf::renderer::settings::experimental::registerRenderMode ) uf::renderer::addRenderMode( &renderMode, name );
metadata.boundGui = true;

View File

@ -28,6 +28,7 @@
#include <uf/ext/ext.h>
#include <uf/ext/ffx/fsr.h>
#include <uf/ext/openvr/openvr.h>
#include "../light/behavior.h"
#include "../voxelizer/behavior.h"
@ -158,11 +159,9 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) {
#endif
renderMode.scale = 1.0f; // ::json["engine"]["ext"]["vulkan"]["framebuffer"]["size"].as(1.0f);
UF_MSG_DEBUG("Geometry render scale: {:.3f}", renderMode.scale);
/*
if ( ::json["engine"]["render modes"]["stereo deferred"].as<bool>() ) {
if ( ext::openvr::enabled ) {
renderMode.metadata.eyes = 2;
}
*/
#if UF_USE_VULKAN
if ( uf::renderer::settings::pipelines::deferred ) {
renderMode.metadata.pipelines.emplace_back(uf::renderer::settings::pipelines::names::deferred);

View File

@ -1707,10 +1707,8 @@ bool uf::graph::tick( pod::Graph::Storage& storage ) {
auto& metadata = entity.getComponent<uf::ObjectBehavior::Metadata>();
auto& transform = entity.getComponent<pod::Transform<>>();
if ( !metadata.system.ignoreGraph ) {
object.previous = object.model;
object.model = uf::transform::model( transform );
}
object.previous = object.model;
object.model = uf::transform::model( transform );
}
objects.emplace_back( object );

File diff suppressed because it is too large Load Diff

View File

@ -16,6 +16,7 @@
#include <uf/engine/graph/graph.h>
#include <uf/engine/ext.h>
#include <uf/ext/ffx/fsr.h>
#include <uf/ext/openvr/openvr.h>
#define BARYCENTRIC 1
#if BARYCENTRIC
@ -117,7 +118,7 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
struct {
size_t id, bary, depth, depth_resolved, uv, normal;
size_t color, scratch, motion, output;
size_t color, scratch, motion, output, outputRightEye;
} attachments = {};
bool blend = true; // !ext::vulkan::settings::invariant::deferredSampling;
@ -169,14 +170,14 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
attachments.color = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
/*.blend =*/ true,
/*.samples =*/ 1,
});
attachments.scratch = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
/*.blend =*/ false,
/*.samples =*/ 1,
/*.mips =*/ mips,
@ -223,6 +224,11 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
metadata.attachments["output"] = attachments.color;
if ( metadata.eyes == 2 ) {
metadata.attachments["left"] = metadata.attachments["output"];
metadata.attachments["right"] = metadata.attachments["scratch"];
}
// First pass: fill the G-Buffer
renderTarget.addPass(
/*.*/ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
@ -449,6 +455,16 @@ void ext::vulkan::DeferredRenderMode::initialize( Device& device ) {
::postprocesses::depthPyramid.atomicCounter.initialize( (const void*) nullptr, sizeof(::AtomicCounter) * 1, uf::renderer::enums::Buffer::STORAGE | VK_BUFFER_USAGE_TRANSFER_DST_BIT );
shader.aliasBuffer("atomicCounterDepth", ::postprocesses::depthPyramid.atomicCounter);
}
if ( ext::openvr::enabled ) {
uf::stl::string vertexShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/vr/stereo.vert.spv");
uf::stl::string fragmentShaderFilename = uf::io::resolveURI(uf::io::root+"/shaders/display/vr/stereo.frag.spv");
blitter.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "vr");
blitter.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vr");
auto& shader = blitter.material.getShader("fragment", "vr");
shader.aliasAttachment("output", this);
}
}
this->build(true);
@ -597,6 +613,12 @@ void ext::vulkan::DeferredRenderMode::build( bool resized ) {
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
blitter.update( descriptor );
}
if ( ext::openvr::enabled ) {
auto descriptor = blitter.descriptor;
descriptor.pipeline = "vr";
blitter.update( descriptor );
}
}
}
void ext::vulkan::DeferredRenderMode::tick() {
@ -1191,6 +1213,63 @@ void ext::vulkan::DeferredRenderMode::createCommandBuffers( const uf::stl::vecto
}
#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");
VkImageSubresourceRange outRange = {};
outRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
outRange.baseMipLevel = 0;
outRange.levelCount = 1;
outRange.baseArrayLayer = 0;
outRange.layerCount = metadata.eyes;
VkImageSubresourceRange scratchRange = outRange;
scratchRange.layerCount = 1;
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
);
VkImageCopy copy = {};
copy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.srcSubresource.baseArrayLayer = 1;
copy.srcSubresource.layerCount = 1;
copy.srcSubresource.mipLevel = 0;
copy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copy.dstSubresource.baseArrayLayer = 0;
copy.dstSubresource.layerCount = 1;
copy.dstSubresource.mipLevel = 0;
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
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));

View File

@ -11,6 +11,7 @@
#include <uf/utils/camera/camera.h>
#include <uf/engine/ext.h>
#include <uf/utils/io/fmt.h>
#include <uf/ext/openvr/openvr.h>
const uf::stl::string ext::vulkan::RenderTargetRenderMode::getType() const {
return "RenderTarget";
@ -212,6 +213,19 @@ void ext::vulkan::RenderTargetRenderMode::initialize( Device& device ) {
}
}
}
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"));
blitter.material.attachShader(vertexShaderFilename, uf::renderer::enums::Shader::VERTEX, "vr");
blitter.material.attachShader(fragmentShaderFilename, uf::renderer::enums::Shader::FRAGMENT, "vr");
{
auto& shader = blitter.material.getShader("fragment", "vr");
shader.aliasAttachment("color", this);
}
}
}
this->build(true);
@ -266,6 +280,12 @@ void ext::vulkan::RenderTargetRenderMode::build( bool resized ) {
descriptor.bind.point = VK_PIPELINE_BIND_POINT_COMPUTE;
blitter.update( descriptor );
}
if ( ext::openvr::enabled && metadata.json["vr"].as<bool>() ) {
auto descriptor = blitter.descriptor;
descriptor.pipeline = "vr";
blitter.update( descriptor );
}
}
void ext::vulkan::RenderTargetRenderMode::tick() {

View File

@ -0,0 +1,250 @@
#if UF_USE_VULKAN
#include <uf/ext/vulkan/vulkan.h>
#include <uf/ext/vulkan/rendermodes/vr.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>
#include <uf/engine/ext.h>
#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";
}
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";
ext::vulkan::RenderMode::initialize( device );
renderTarget.device = &device;
struct {
size_t left, right, depth;
} attachments = {};
attachments.left = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
/*.blend =*/ true,
/*.samples =*/ 1,
});
attachments.right = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format =*/ ext::vulkan::settings::pipelines::hdr ? enums::Format::HDR : enums::Format::SDR,
/*.layout = */ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
/*.usage =*/ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
/*.blend =*/ true,
/*.samples =*/ 1,
});
attachments.depth = renderTarget.attach(RenderTarget::Attachment::Descriptor{
/*.format = */ext::vulkan::settings::formats::depth,
/*.layout = */VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
/*.usage = */VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT,
/*.blend = */false,
/*.samples = */1,
});
metadata.attachments["left"] = attachments.left;
metadata.attachments["right"] = attachments.right;
metadata.attachments["output"] = attachments.left;
renderTarget.addPass(
/*.*/ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
/*.colors =*/ { attachments.left, attachments.right },
/*.inputs =*/ {},
/*.resolve =*/{},
/*.depth = */ attachments.depth,
/*.layer = */0,
/*.autoBuildPipeline =*/ true
);
renderTarget.initialize( device );
blitter.process = false;
}
void ext::vulkan::VrRenderMode::createCommandBuffers(const uf::stl::vector<ext::vulkan::Graphic*>& graphics) {
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);
VkCommandBufferBeginInfo cmdBufInfo = ext::vulkan::initializers::commandBufferBeginInfo();
cmdBufInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; // ext::vulkan::device.queueFamilyIndices.graphics; //VK_QUEUE_FAMILY_IGNORED
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.baseArrayLayer = 0;
imageMemoryBarrier.subresourceRange.layerCount = 1;
imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
uf::stl::vector<RenderMode*> layers = ext::vulkan::getRenderModes(uf::stl::vector<uf::stl::string>{"Deferred", "Compute:RT", "RenderTarget"}, false);
float depthClear = uf::matrix::reverseInfiniteProjection ? 0.0f : 1.0f;
uf::stl::vector<VkClearValue> clearValues;
for ( auto& attachment : renderTarget.attachments ) {
pod::Vector4f clearColor = {0, 0, 0, 0};
auto& clearValue = clearValues.emplace_back();
if ( attachment.descriptor.usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ) {
clearValue.color.float32[0] = clearColor[0];
clearValue.color.float32[1] = clearColor[1];
clearValue.color.float32[2] = clearColor[2];
clearValue.color.float32[3] = clearColor[3];
} else if ( attachment.descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ) {
clearValue.depthStencil = { depthClear, 0 };
}
}
auto& commands = getCommands();
for (size_t frame = 0; frame < commands.size(); ++frame) {
auto& commandBuffer = commands[frame];
VK_CHECK_RESULT(vkBeginCommandBuffer(commandBuffer, &cmdBufInfo));
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "begin" );
{
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = nullptr;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width = width;
renderPassBeginInfo.renderArea.extent.height = height;
renderPassBeginInfo.clearValueCount = clearValues.size();
renderPassBeginInfo.pClearValues = &clearValues[0];
renderPassBeginInfo.renderPass = renderTarget.renderPass;
renderPassBeginInfo.framebuffer = renderTarget.framebuffers[frame];
// Update dynamic viewport state
VkViewport viewport = {};
viewport.width = (float) width;
viewport.height = (float) height;
viewport.minDepth = (float) 0.0f;
viewport.maxDepth = (float) 1.0f;
// Update dynamic scissor state
VkRect2D scissor = {};
scissor.extent.width = width;
scissor.extent.height = height;
scissor.offset.x = 0;
scissor.offset.y = 0;
size_t subpasses = renderTarget.passes.size();
size_t currentPass = 0;
// pre-renderpass commands
VK_COMMAND_BUFFER_CALLBACK( CALLBACK_BEGIN, commandBuffer, frame, {
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "callback[begin]" );
} );
{
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::BEGIN, "renderPass[begin]" );
vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
for ( auto currentPass = 0; currentPass < 2; ++currentPass ) {
size_t currentDraw = 0;
for ( auto _ : layers ) {
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);
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, ::fmt::format("blitter[{}: {}]", layer->getName(), layer->getType()) );
blitter.record(commandBuffer, descriptor, currentPass, currentDraw++, frame);
}
}
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]" );
} );
}
device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::END, "end" );
VK_CHECK_RESULT(vkEndCommandBuffer(commandBuffer));
}
}
void ext::vulkan::VrRenderMode::build( bool resized ) {
ext::vulkan::RenderMode::build();
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);
// (re)initialize pipelines
if ( blitter.process ) {
blitter.descriptor.bind.width = width;
blitter.descriptor.bind.height = height;
blitter.update( blitter.descriptor );
}
}
void ext::vulkan::VrRenderMode::tick() {
ext::vulkan::RenderMode::tick();
bool resized = this->width == 0 && this->height == 0 && (ext::vulkan::states::resized || this->resized);
bool rebuild = resized || ext::vulkan::states::rebuild || this->rebuild;
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);
if ( resized ) {
this->resized = false;
renderTarget.initialize( *renderTarget.device );
}
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() {
ext::vulkan::RenderMode::destroy();
}
void ext::vulkan::VrRenderMode::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;
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, {} );
ext::openvr::submit();
this->executed = true;
}
#endif

View File

@ -27,6 +27,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
size_t index = attachments.size();
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);
uint8_t layers = descriptor.layers > 0 ? descriptor.layers : this->views;
if ( attachment ) {
for ( auto& view : attachment->views ) {
@ -66,12 +67,13 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
attachment->descriptor.width = width;
attachment->descriptor.height = height;
attachment->descriptor.layers = layers;
if ( attachment->descriptor.mips <= 1 ) {
attachment->descriptor.mips = 1;
} else {
attachment->descriptor.mips = uf::vector::mips( pod::Vector2ui{ width, height } );
}
attachment->views.resize(this->views * attachment->descriptor.mips);
attachment->views.resize(layers * attachment->descriptor.mips);
bool isSwapchain = attachment->descriptor.layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
bool isDepth = attachment->descriptor.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
@ -86,7 +88,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
subresourceRange.levelCount = 1;
subresourceRange.baseArrayLayer = 0;
subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.layerCount = this->views;
subresourceRange.layerCount = layers;
auto commandBuffer = device->fetchCommandBuffer(uf::renderer::QueueEnum::GRAPHICS);
for ( size_t i = 0; i < ext::vulkan::swapchain.buffers; ++i ) {
@ -123,13 +125,13 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
imageCreateInfo.format = attachment->descriptor.format;
imageCreateInfo.extent = { width, height, 1 };
imageCreateInfo.mipLevels = attachment->descriptor.mips;
imageCreateInfo.arrayLayers = this->views;
imageCreateInfo.arrayLayers = layers;
imageCreateInfo.samples = ext::vulkan::sampleCount( attachment->descriptor.samples );
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = attachment->descriptor.usage;
imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
if ( this->views == 6 ) {
if ( layers == 6 ) {
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
}
@ -152,8 +154,8 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
VkImageViewCreateInfo imageView = {};
imageView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
if ( this->views > 1 ) {
imageView.viewType = this->views == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
if ( layers > 1 ) {
imageView.viewType = layers == 6 ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
}
imageView.format = attachment->descriptor.format;
imageView.subresourceRange = {};
@ -161,7 +163,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
imageView.subresourceRange.baseMipLevel = 0;
imageView.subresourceRange.baseArrayLayer = 0;
imageView.subresourceRange.levelCount = attachment->descriptor.mips;
imageView.subresourceRange.layerCount = this->views;
imageView.subresourceRange.layerCount = layers;
imageView.image = attachment->image;
VK_CHECK_RESULT(vkCreateImageView(*device, &imageView, nullptr, &attachment->view));
VK_REGISTER_HANDLE( attachment->view );
@ -173,7 +175,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
}
size_t viewIndex = 0;
for ( size_t layer = 0; layer < this->views; ++layer ) {
for ( size_t layer = 0; layer < layers; ++layer ) {
imageView.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageView.subresourceRange.levelCount = 1;
imageView.subresourceRange.layerCount = 1;
@ -210,7 +212,7 @@ size_t ext::vulkan::RenderTarget::attach( const Attachment::Descriptor& descript
subresourceRange.baseMipLevel = 0;
subresourceRange.baseArrayLayer = 0;
subresourceRange.levelCount = attachment->descriptor.mips;
subresourceRange.layerCount = this->views;
subresourceRange.layerCount = layers;
subresourceRange.aspectMask = isDepth ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
uf::renderer::Texture::setImageLayout( commandBuffer, attachment->image, VK_IMAGE_LAYOUT_UNDEFINED, attachment->descriptor.layout, subresourceRange );
device->flushCommandBuffer(commandBuffer, uf::renderer::QueueEnum::GRAPHICS);
@ -493,7 +495,7 @@ void ext::vulkan::RenderTarget::destroy() {
attachment.view = VK_NULL_HANDLE;
}
}
for ( size_t i = 0; i < this->views; ++i ) {
for ( size_t i = 0; i < attachment.views.size(); ++i ) {
vkDestroyImageView(*device, attachment.views[i], nullptr);
VK_UNREGISTER_HANDLE( attachment.views[i] );
}

View File

@ -13,8 +13,8 @@ pod::Vector3f uf::camera::eye( const pod::Camera& camera, int i ) {
if ( i < 0 ) i = 0;
pod::Vector3f position = uf::transform::flatten( camera.transform ).position;
#if UF_USE_OPENVR
if ( camera.stereoscopic && ext::openvr::context ) {
position += ext::openvr::hmdPosition( eye == 0 ? vr::Eye_Left : vr::Eye_Right );
if ( camera.stereoscopic && ext::openvr::enabled ) {
position += ext::openvr::hmdPosition( i == 0 ? vr::Eye_Left : vr::Eye_Right );
}
#endif
return position;
@ -39,10 +39,8 @@ void uf::camera::projection( pod::Camera& camera, const pod::Matrix4f& mat, int
}
void uf::camera::update( pod::Camera& camera ) {
#if UF_USE_OPENVR
if ( this->stereoscopic && ext::openvr::context ) {
camera.transform.orientation = uf::quaternion::identity();
if ( camera.stereoscopic && ext::openvr::enabled ) {
auto view = uf::matrix::inverse( uf::transform::model( camera.transform ) );
camera.transform.orientation = ext::openvr::hmdQuaternion();
uf::camera::view( camera, ext::openvr::hmdViewMatrix(vr::Eye_Left, view ), 0 );
uf::camera::view( camera, ext::openvr::hmdViewMatrix(vr::Eye_Right, view ), 1 );

View File

@ -1,5 +1,5 @@
ifneq (,$(findstring -DUF_DEV_ENV,$(FLAGS)))
REQ_DEPS += meshoptimizer toml xatlas curl dc:texconv # ffx:sdk vall_e cpptrace # openvr # ncurses draco discord bullet ultralight-ux
REQ_DEPS += meshoptimizer toml xatlas curl dc:texconv ffx:sdk openvr # vall_e cpptrace # ncurses draco discord ultralight-ux
FLAGS += -march=native -g # -flto # -g
endif