Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds multiview to CubeXr #459

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions include/ppx/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ struct StandardOptions
#if defined(PPX_BUILD_XR)
std::shared_ptr<KnobFlag<std::pair<int, int>>> pXrUiResolution;
std::shared_ptr<KnobFlag<std::vector<std::string>>> pXrRequiredExtensions;
std::shared_ptr<KnobFlag<bool>> pXrEnableMultiview;
#endif

std::shared_ptr<KnobFlag<std::vector<std::string>>> pAssetsPaths;
Expand Down Expand Up @@ -119,11 +120,6 @@ struct ApplicationSettings
{
bool enable = false;

// Multiview will create one swapchain with layers per view
// One Application::Render then should use multiview shaders
// to render to both layers, as opposed to non multiview
// where there is one swapchain per view, each with a ::Render
bool enableMultiView = false;
// Whether to create depth swapchains in addition to color swapchains,
// and submit the depth info to the runtime as an additional layer.
bool enableDepthSwapchain = false;
Expand Down Expand Up @@ -211,6 +207,7 @@ struct ApplicationSettings
#if defined(PPX_BUILD_XR)
std::pair<int, int> xrUiResolution = std::make_pair(0, 0);
std::vector<std::string> xrRequiredExtensions = {};
bool xrEnableMultiview = false;
#endif
} standardKnobsDefaultValue;
};
Expand Down
2 changes: 1 addition & 1 deletion projects/cube_xr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ add_samples_for_all_apis(
"CubeXr.h"
"CubeXr.cpp"
"main.cpp"
SHADER_DEPENDENCIES "shader_vertex_colors")
SHADER_DEPENDENCIES "shader_vertex_colors_multi")
46 changes: 31 additions & 15 deletions projects/cube_xr/CubeXr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void CubeXrApp::Setup()
// Uniform buffer
{
grfx::BufferCreateInfo bufferCreateInfo = {};
bufferCreateInfo.size = PPX_MINIMUM_UNIFORM_BUFFER_SIZE;
bufferCreateInfo.size = std::max(sizeof(UniformBufferData), (uint64_t)PPX_MINIMUM_UNIFORM_BUFFER_SIZE);
bufferCreateInfo.usageFlags.bits.uniformBuffer = true;
bufferCreateInfo.memoryUsage = grfx::MEMORY_USAGE_CPU_TO_GPU;

Expand Down Expand Up @@ -68,12 +68,12 @@ void CubeXrApp::Setup()

// Pipeline
{
std::vector<char> bytecode = LoadShader("basic/shaders", "VertexColors.vs");
std::vector<char> bytecode = LoadShader("basic/shaders", "VertexColorsMulti.vs");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you find the spec language that says the view index is going to be 0 if there is not multiview in the shader? Otherwise maybe better to use VertexColors if there is no multiview?

PPX_ASSERT_MSG(!bytecode.empty(), "VS shader bytecode load failed");
grfx::ShaderModuleCreateInfo shaderCreateInfo = {static_cast<uint32_t>(bytecode.size()), bytecode.data()};
PPX_CHECKED_CALL(GetDevice()->CreateShaderModule(&shaderCreateInfo, &mVS));

bytecode = LoadShader("basic/shaders", "VertexColors.ps");
bytecode = LoadShader("basic/shaders", "VertexColorsMulti.ps");
PPX_ASSERT_MSG(!bytecode.empty(), "PS shader bytecode load failed");
shaderCreateInfo = {static_cast<uint32_t>(bytecode.size()), bytecode.data()};
PPX_CHECKED_CALL(GetDevice()->CreateShaderModule(&shaderCreateInfo, &mPS));
Expand Down Expand Up @@ -103,6 +103,8 @@ void CubeXrApp::Setup()
gpCreateInfo.outputState.renderTargetFormats[0] = GetSwapchain()->GetColorFormat();
gpCreateInfo.outputState.depthStencilFormat = GetSwapchain()->GetDepthFormat();
gpCreateInfo.pPipelineInterface = mPipelineInterface;
gpCreateInfo.multiViewState.viewMask = GetXrComponent().GetDefaultViewMask();
gpCreateInfo.multiViewState.correlationMask = GetXrComponent().GetDefaultViewMask();
PPX_CHECKED_CALL(GetDevice()->CreateGraphicsPipeline(&gpCreateInfo, &mPipeline));
}

Expand Down Expand Up @@ -201,11 +203,13 @@ void CubeXrApp::Setup()

void CubeXrApp::Render()
{
PerFrame& frame = mPerFrame[0];
uint32_t imageIndex = UINT32_MAX;
uint32_t currentViewIndex = 0;
PerFrame& frame = mPerFrame[0];
uint32_t imageIndex = UINT32_MAX;
uint32_t currentViewIndex = 0;
XrComponent& xrComponent = GetXrComponent();

if (IsXrEnabled()) {
currentViewIndex = GetXrComponent().GetCurrentViewIndex();
currentViewIndex = xrComponent.GetCurrentViewIndex();
}

// Render UI into a different composition layer.
Expand Down Expand Up @@ -269,20 +273,32 @@ void CubeXrApp::Render()
// Update uniform buffer.
{
float t = GetElapsedSeconds();
float4x4 P = glm::perspective(glm::radians(60.0f), GetWindowAspect(), 0.001f, 10000.0f);
float4x4 V = glm::lookAt(float3(0, 0, 0), float3(0, 0, 1), float3(0, 1, 0));
float4x4 M = glm::translate(float3(0, 0, -3)) * glm::rotate(t, float3(0, 0, 1)) * glm::rotate(t, float3(0, 1, 0)) * glm::rotate(t, float3(1, 0, 0));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we rework this logic a bit?

  • I am not sure if this currently works with non-XR, we have to make sure it still works
  • Can we add a GetCamera(viewIndex) and get the matrices that way, then we wouldn't have to add additional methods to the xr component


if (IsXrEnabled()) {
const Camera& camera = GetXrComponent().GetCamera();
P = camera.GetProjectionMatrix();
V = camera.GetViewMatrix();
xrComponent.SetCurrentViewIndex(0);
frame.uniform_buffer_data.M[0] = xrComponent.GetCamera().GetViewProjectionMatrix() * M;

xrComponent.SetCurrentViewIndex(1);
frame.uniform_buffer_data.M[1] = xrComponent.GetCamera().GetViewProjectionMatrix() * M;
}
else {
const Camera& camera = xrComponent.GetCamera();
float4x4 P = camera.GetProjectionMatrix();
float4x4 V = camera.GetViewMatrix();
frame.uniform_buffer_data.M[0] = frame.uniform_buffer_data.M[1] = P * V * M;
}

// If multiview is active, we have one render pass with Left/Right poses loaded.
// If not multiview, this entire render call will happen again, and we switch to current view index.

if (!xrComponent.IsMultiView()) {
frame.uniform_buffer_data.M[0] = frame.uniform_buffer_data.M[IsXrEnabled() ? xrComponent.GetCurrentViewIndex() : 0];
}
float4x4 M = glm::translate(float3(0, 0, -3)) * glm::rotate(t, float3(0, 0, 1)) * glm::rotate(t, float3(0, 1, 0)) * glm::rotate(t, float3(1, 0, 0));
float4x4 mat = P * V * M;

void* pData = nullptr;
PPX_CHECKED_CALL(mUniformBuffer->MapMemory(0, &pData));
memcpy(pData, &mat, sizeof(mat));
memcpy(pData, &frame.uniform_buffer_data, sizeof(frame.uniform_buffer_data));
mUniformBuffer->UnmapMemory();
}

Expand Down
9 changes: 9 additions & 0 deletions projects/cube_xr/CubeXr.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ class CubeXrApp
virtual void Render() override;

private:
struct UniformBufferData
{
// Pose of each Cube
// One for each eye, but second only used in multi-view
ppx::float4x4 M[2];
};

struct PerFrame
{
grfx::CommandBufferPtr cmd;
Expand All @@ -36,6 +43,8 @@ class CubeXrApp
grfx::SemaphorePtr renderCompleteSemaphore;
grfx::FencePtr renderCompleteFence;

UniformBufferData uniform_buffer_data = {};

// XR UI per frame elements.
grfx::CommandBufferPtr uiCmd;
grfx::FencePtr uiRenderCompleteFence;
Expand Down
8 changes: 6 additions & 2 deletions src/ppx/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ Result Application::InitializeGrfxDevice()
ci.pVulkanDeviceFeatures = nullptr;
ci.supportShadingRateMode = mSettings.grfx.device.supportShadingRateMode;
#if defined(PPX_BUILD_XR)
ci.multiView = IsXrEnabled() && mSettings.xr.enableMultiView;
ci.multiView = IsXrEnabled() && mStandardOpts.pXrEnableMultiview->GetValue();
ci.pXrComponent = IsXrEnabled() ? &mXrComponent : nullptr;
#endif

Expand Down Expand Up @@ -682,6 +682,10 @@ void Application::InitStandardKnobs()
"to the base extensions. Any required extensions that are not supported by the "
"target system will cause the application to immediately exit.");
mStandardOpts.pXrRequiredExtensions->SetFlagParameters("<extension>");

GetKnobManager().InitKnob(&mStandardOpts.pXrEnableMultiview, "xr-enable-multiview", mSettings.standardKnobsDefaultValue.xrEnableMultiview);
mStandardOpts.pXrEnableMultiview->SetFlagDescription(
"Specify whether or not multiview should be enabled for the application.");
#endif

GetKnobManager().InitKnob(&mStandardOpts.pShadingRateMode, "shading-rate-mode", "");
Expand Down Expand Up @@ -973,7 +977,7 @@ void Application::InitializeXRComponentBeforeGrfxDeviceInit()
createInfo.enableDebug = mSettings.grfx.enableDebug;
createInfo.enableQuadLayer = mSettings.enableImGui;
createInfo.enableDepthSwapchain = mSettings.xr.enableDepthSwapchain;
createInfo.enableMultiView = mSettings.xr.enableMultiView;
createInfo.enableMultiView = mStandardOpts.pXrEnableMultiview->GetValue();
const auto resolution = mStandardOpts.pResolution->GetValue();
const bool hasResolutionFlag = (resolution.first > 0 && resolution.second > 0);
if (hasResolutionFlag) {
Expand Down
Loading