• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Razakhel / RaZ / 11821554006

13 Nov 2024 04:20PM UTC coverage: 74.443% (-0.007%) from 74.45%
11821554006

push

github

Razakhel
[XR/XrSession] Requesting frame rendering returns whether it has been

- This is used afterward to avoid copying the frame to the window

- It happens for the first few frames, notably when the session hasn't been started yet (the RenderSystem is updated while the XrSystem still hasn't been)

0 of 8 new or added lines in 3 files covered. (0.0%)

1 existing line in 1 file now uncovered.

8054 of 10819 relevant lines covered (74.44%)

1816.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/RaZ/XR/XrSession.cpp
1
#include "RaZ/Data/Color.hpp"
2
#include "RaZ/Math/Quaternion.hpp"
3
#include "RaZ/Render/Renderer.hpp"
4
#include "RaZ/Utils/Logger.hpp"
5
#include "RaZ/XR/XrContext.hpp"
6
#include "RaZ/XR/XrSession.hpp"
7

8
#if defined(XR_OS_WINDOWS)
9
#define WIN32_LEAN_AND_MEAN
10
#include <Windows.h>
11
#include <Unknwn.h>
12
#endif
13

14
#include "GL/glew.h"
15
#if defined(XR_OS_WINDOWS)
16
#define GLFW_EXPOSE_NATIVE_WIN32
17
#define GLFW_EXPOSE_NATIVE_WGL
18
#elif defined(XR_OS_LINUX)
19
#define GLFW_EXPOSE_NATIVE_X11
20
#define GLFW_EXPOSE_NATIVE_GLX
21
#endif
22
#include "GLFW/glfw3.h"
23
#include "GLFW/glfw3native.h"
24

25
#include "openxr/openxr.h"
26
#include "openxr/openxr_platform.h"
27

28
#include "tracy/Tracy.hpp"
29
#include "tracy/TracyOpenGL.hpp"
30

31
#include <algorithm>
32
#include <array>
33
#include <stdexcept>
34

35
namespace Raz {
36

37
namespace {
38

39
constexpr std::string_view swapchainCopySource = R"(
40
  in vec2 fragTexcoords;
41

42
  uniform sampler2D uniFinalColorBuffer;
43
  uniform sampler2D uniFinalDepthBuffer;
44

45
  layout(location = 0) out vec4 fragColor;
46

47
  void main() {
48
    fragColor     = texture(uniFinalColorBuffer, fragTexcoords).rgba;
49
    // Gamma uncorrection, as the swapchain seems to apply it itself
50
    fragColor.rgb = pow(fragColor.rgb, vec3(2.2));
51
    gl_FragDepth  = texture(uniFinalDepthBuffer, fragTexcoords).r;
52
  }
53
)";
54

55
const char* getResultStr(XrInstance instance, XrResult result) {
×
56
  static std::array<char, XR_MAX_RESULT_STRING_SIZE> errorStr {};
57
  xrResultToString(instance, result, errorStr.data());
×
58
  return errorStr.data();
×
59
}
60

61
std::string getErrorStr(const std::string& errorMsg, XrResult result, XrInstance instance) {
×
62
  return "[XrSession] " + errorMsg + ": " + getResultStr(instance, result) + " (" + std::to_string(result) + ')';
×
63
}
64

65
void checkLog(XrResult result, const std::string& errorMsg, XrInstance instance) {
×
66
  if (XR_SUCCEEDED(result))
×
67
    return;
×
68

69
  Logger::error(getErrorStr(errorMsg, result, instance));
×
70
}
71

72
void checkThrow(XrResult result, const std::string& errorMsg, XrInstance instance) {
×
73
  if (XR_SUCCEEDED(result))
×
74
    return;
×
75

76
  throw std::runtime_error(getErrorStr(errorMsg, result, instance));
×
77
}
78

79
#if defined(XR_USE_PLATFORM_WIN32)
80
using GraphicsBinding = XrGraphicsBindingOpenGLWin32KHR;
81
#elif defined(XR_USE_PLATFORM_XLIB)
82
using GraphicsBinding = XrGraphicsBindingOpenGLXlibKHR;
83
#endif
84

85
GraphicsBinding getGraphicsBinding() {
×
86
  GLFWwindow* window = glfwGetCurrentContext();
×
87
  GraphicsBinding graphicsBinding {};
×
88

89
#if defined(XR_USE_PLATFORM_WIN32)
90
  graphicsBinding.type  = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
91
  graphicsBinding.hDC   = GetDC(glfwGetWin32Window(window));
92
  graphicsBinding.hGLRC = glfwGetWGLContext(window);
93
#elif defined(XR_USE_PLATFORM_XLIB)
94
  Display* x11Display = glfwGetX11Display();
×
95

96
  // TODO: some fields can't be directly filled with what GLFW exposes; see https://github.com/glfw/glfw/issues/2129
97

98
  // TODO: unless there's a way to easily recover the FBConfig from a GLXContext (related GLFW PR: https://github.com/glfw/glfw/pull/1925), it has to be done
99
  //  manually; see https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/dfe3ad67f11ab71a64b2c75d6b7a97034b9766fd/src/common/gfxwrapper_opengl.c#L1016-L1077
100
  GLXFBConfig fbConfig {};
×
101
  graphicsBinding.type        = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
×
102
  graphicsBinding.xDisplay    = x11Display;
×
103
  graphicsBinding.visualid    = static_cast<uint32_t>(glXGetVisualFromFBConfig(x11Display, fbConfig)->visualid);
×
104
  graphicsBinding.glxFBConfig = fbConfig;
×
105
  graphicsBinding.glxDrawable = glXGetCurrentDrawable();
×
106
  graphicsBinding.glxContext  = glfwGetGLXContext(window);
×
107
#endif
108

109
  return graphicsBinding;
×
110
}
111

112
int64_t selectColorSwapchainFormat(const std::vector<int64_t>& formats) {
×
113
  constexpr std::array<int64_t, 4> supportedColorSwapchainFormats = {
×
114
    GL_RGB10_A2,
115
    GL_RGBA16F,
116
    // The following values should only be used as a fallback, as they are linear color formats without enough bits for color depth, thus leading to banding
117
    GL_RGBA8,
118
    GL_RGBA8_SNORM
119
  };
120

121
  const auto formatIter = std::find_first_of(formats.cbegin(), formats.cend(),
×
122
                                             supportedColorSwapchainFormats.cbegin(), supportedColorSwapchainFormats.cend());
123

124
  if (formatIter == formats.cend())
×
125
    return 0;
×
126

127
  return *formatIter;
×
128
}
129

130
int64_t selectDepthSwapchainFormat(const std::vector<int64_t>& formats) {
×
131
  constexpr std::array<int64_t, 4> supportedDepthSwapchainFormats = {
×
132
    GL_DEPTH_COMPONENT32F,
133
    GL_DEPTH_COMPONENT32,
134
    GL_DEPTH_COMPONENT24,
135
    GL_DEPTH_COMPONENT16
136
  };
137

138
  const auto formatIter = std::find_first_of(formats.cbegin(), formats.cend(),
×
139
                                             supportedDepthSwapchainFormats.cbegin(), supportedDepthSwapchainFormats.cend());
140

141
  if (formatIter == formats.cend())
×
142
    return 0;
×
143

144
  return *formatIter;
×
145
}
146

147
} // namespace
148

149
struct XrSession::RenderLayerInfo {
150
  XrTime predictedDisplayTime {};
151
  std::vector<XrCompositionLayerBaseHeader*> layers;
152
  XrCompositionLayerProjection layerProjection{ XR_TYPE_COMPOSITION_LAYER_PROJECTION };
153
  std::vector<XrCompositionLayerProjectionView> layerProjectionViews;
154
};
155

156
enum class XrSession::SwapchainType : uint8_t {
157
  COLOR,
158
  DEPTH
159
};
160

161
XrSession::XrSession(const XrContext& context) : m_instance{ context.m_instance },
×
162
                                                 m_swapchainCopyPass(FragmentShader::loadFromSource(swapchainCopySource), "Swapchain copy pass") {
×
163
  ZoneScopedN("XrSession::XrSession");
164

165
  Logger::debug("[XrSession] Creating session...");
×
166

167
  if (m_instance == XR_NULL_HANDLE)
×
168
    throw std::runtime_error("[XrSession] The XR instance must be valid");
×
169

170
  if (!Renderer::isInitialized())
×
171
    throw std::runtime_error("[XrSession] The renderer must be initialized");
×
172

173
  PFN_xrGetOpenGLGraphicsRequirementsKHR xrGetOpenGLGraphicsRequirementsKHR {};
×
174
  checkLog(xrGetInstanceProcAddr(m_instance,
×
175
                                 "xrGetOpenGLGraphicsRequirementsKHR",
176
                                 reinterpret_cast<PFN_xrVoidFunction*>(&xrGetOpenGLGraphicsRequirementsKHR)),
177
           "Failed to get OpenGL graphics requirements get function",
178
           m_instance);
179
  XrGraphicsRequirementsOpenGLKHR graphicsRequirements {};
×
180
  graphicsRequirements.type = XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR;
×
181
  checkLog(xrGetOpenGLGraphicsRequirementsKHR(m_instance, context.m_systemId, &graphicsRequirements),
×
182
           "Failed to get graphics requirements for OpenGL", m_instance);
183

184
  const XrVersion graphicsApiVersion = XR_MAKE_VERSION(Renderer::getMajorVersion(), Renderer::getMinorVersion(), 0);
×
185
  if (graphicsRequirements.minApiVersionSupported > graphicsApiVersion) {
×
186
    const uint16_t requiredMajorVersion = XR_VERSION_MAJOR(graphicsRequirements.minApiVersionSupported);
×
187
    const uint16_t requiredMinorVersion = XR_VERSION_MINOR(graphicsRequirements.minApiVersionSupported);
×
188
    throw std::runtime_error("[XrSession] The current OpenGL version "
×
189
                             + std::to_string(Renderer::getMajorVersion()) + '.' + std::to_string(Renderer::getMinorVersion())
×
190
                             + " does not meet the minimum required version "
×
191
                             + std::to_string(requiredMajorVersion) + '.' + std::to_string(requiredMinorVersion)
×
192
                             + " for OpenXR");
×
193
  }
194

195
  const GraphicsBinding graphicsBinding = getGraphicsBinding();
×
196
  XrSessionCreateInfo sessionCreateInfo {};
×
197
  sessionCreateInfo.type        = XR_TYPE_SESSION_CREATE_INFO;
×
198
  sessionCreateInfo.next        = &graphicsBinding;
×
199
  sessionCreateInfo.createFlags = 0;
×
200
  sessionCreateInfo.systemId    = context.m_systemId;
×
201
  checkThrow(xrCreateSession(m_instance, &sessionCreateInfo, &m_handle), "Failed to create session", m_instance);
×
202

203
  createReferenceSpace();
×
204

205
  RenderShaderProgram& swapchainCopyProgram = m_swapchainCopyPass.getProgram();
×
206
  swapchainCopyProgram.setAttribute(0, "uniFinalColorBuffer");
×
207
  swapchainCopyProgram.setAttribute(1, "uniFinalDepthBuffer");
×
208
  swapchainCopyProgram.sendAttributes();
×
209

210
  constexpr DrawBuffer drawBuffer = DrawBuffer::COLOR_ATTACHMENT0;
×
211
  Renderer::bindFramebuffer(m_swapchainCopyPass.getFramebuffer().getIndex(), FramebufferType::DRAW_FRAMEBUFFER);
×
212
  Renderer::setDrawBuffers(1, &drawBuffer);
×
213
  Renderer::bindFramebuffer(0);
×
214

215
  Logger::debug("[XrSession] Created session");
×
216
}
×
217

218
void XrSession::begin(unsigned int viewConfigType) {
×
219
  Logger::debug("[XrSession] Beginning session...");
×
220

221
  XrSessionBeginInfo sessionBeginInfo {};
×
222
  sessionBeginInfo.type                         = XR_TYPE_SESSION_BEGIN_INFO;
×
223
  sessionBeginInfo.primaryViewConfigurationType = static_cast<XrViewConfigurationType>(viewConfigType);
×
224
  checkLog(xrBeginSession(m_handle, &sessionBeginInfo), "Failed to begin session", m_instance);
×
225

226
  Logger::debug("[XrSession] Began session");
×
227
}
×
228

229
void XrSession::end() {
×
230
  Logger::debug("[XrSession] Ending session...");
×
231
  checkLog(xrEndSession(m_handle), "Failed to end session", m_instance);
×
232
  Logger::debug("[XrSession] Ended session");
×
233
}
×
234

NEW
235
bool XrSession::renderFrame(const std::vector<XrViewConfigurationView>& viewConfigViews,
×
236
                            unsigned int viewConfigType,
237
                            unsigned int environmentBlendMode,
238
                            const ViewRenderFunc& viewRenderFunc) {
239
  ZoneScopedN("XrSession::renderFrame");
240

241
  if (!m_isRunning)
×
NEW
242
    return false;
×
243

244
  XrFrameWaitInfo frameWaitInfo {};
×
245
  frameWaitInfo.type = XR_TYPE_FRAME_WAIT_INFO;
×
246
  XrFrameState frameState {};
×
247
  frameState.type = XR_TYPE_FRAME_STATE;
×
248
  checkLog(xrWaitFrame(m_handle, &frameWaitInfo, &frameState), "Failed to wait for the XR frame", m_instance);
×
249

250
  XrFrameBeginInfo frameBeginInfo {};
×
251
  frameBeginInfo.type = XR_TYPE_FRAME_BEGIN_INFO;
×
252
  checkLog(xrBeginFrame(m_handle, &frameBeginInfo), "Failed to begin the XR frame", m_instance);
×
253

254
  RenderLayerInfo renderLayerInfo;
×
255
  // TODO: either the application should use this display time, or the application's global & delta times should be used here somehow
256
  //  See:
257
  //  - https://registry.khronos.org/OpenXR/specs/1.0/man/html/xrWaitFrame.html#_description
258
  //  - https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrTime.html
259
  //  - https://registry.khronos.org/OpenXR/specs/1.0/man/html/XR_KHR_convert_timespec_time.html
260
  renderLayerInfo.predictedDisplayTime = frameState.predictedDisplayTime;
×
261

262
  const bool isSessionActive = (m_state == XR_SESSION_STATE_SYNCHRONIZED || m_state == XR_SESSION_STATE_VISIBLE || m_state == XR_SESSION_STATE_FOCUSED);
×
263
  if (isSessionActive && frameState.shouldRender && renderLayer(renderLayerInfo, viewConfigViews, viewConfigType, viewRenderFunc))
×
264
    renderLayerInfo.layers.emplace_back(reinterpret_cast<XrCompositionLayerBaseHeader*>(&renderLayerInfo.layerProjection));
×
265

266
  {
267
    ZoneNamedN(endFrameZone, "xrEndFrame", true);
268
    TracyGpuZone("xrEndFrame")
269

270
    XrFrameEndInfo frameEndInfo {};
×
271
    frameEndInfo.type                 = XR_TYPE_FRAME_END_INFO;
×
272
    frameEndInfo.displayTime          = frameState.predictedDisplayTime;
×
273
    frameEndInfo.environmentBlendMode = static_cast<XrEnvironmentBlendMode>(environmentBlendMode);
×
274
    frameEndInfo.layerCount           = static_cast<uint32_t>(renderLayerInfo.layers.size());
×
275
    frameEndInfo.layers               = renderLayerInfo.layers.data();
×
276
    checkLog(xrEndFrame(m_handle, &frameEndInfo), "Failed to end the XR frame", m_instance);
×
277
  }
278

NEW
279
  return !renderLayerInfo.layers.empty();
×
UNCOV
280
}
×
281

282
XrSession::~XrSession() {
×
283
  if (m_handle == XR_NULL_HANDLE)
×
284
    return;
×
285

286
  Logger::debug("[XrSession] Destroying session...");
×
287

288
  destroySwapchains();
×
289
  destroyReferenceSpace();
×
290
  checkLog(xrDestroySession(m_handle), "Failed to destroy session", m_instance);
×
291

292
  Logger::debug("[XrSession] Destroyed session");
×
293
}
×
294

295
void XrSession::createSwapchains(const std::vector<XrViewConfigurationView>& viewConfigViews) {
×
296
  ZoneScopedN("XrSession::createSwapchains");
297

298
  Logger::debug("[XrSession] Creating swapchains...");
×
299

300
  uint32_t formatCount {};
×
301
  checkLog(xrEnumerateSwapchainFormats(m_handle, 0, &formatCount, nullptr), "Failed to get swapchain format count", m_instance);
×
302
  std::vector<int64_t> formats(formatCount);
×
303
  checkLog(xrEnumerateSwapchainFormats(m_handle, formatCount, &formatCount, formats.data()), "Failed to enumerate swapchain formats", m_instance);
×
304

305
  if (selectDepthSwapchainFormat(formats) == 0)
×
306
    Logger::error("[XrSession] Failed to find a supported depth swapchain format");
×
307

308
  m_colorSwapchains.resize(viewConfigViews.size());
×
309
  m_depthSwapchains.resize(viewConfigViews.size());
×
310
  m_swapchainImages.reserve(viewConfigViews.size());
×
311

312
  for (std::size_t viewIndex = 0; viewIndex < viewConfigViews.size(); ++viewIndex) {
×
313
    XrSwapchain& colorSwapchain = m_colorSwapchains[viewIndex];
×
314
    XrSwapchain& depthSwapchain = m_depthSwapchains[viewIndex];
×
315

316
    XrSwapchainCreateInfo swapchainCreateInfo {};
×
317
    swapchainCreateInfo.type        = XR_TYPE_SWAPCHAIN_CREATE_INFO;
×
318
    swapchainCreateInfo.createFlags = 0;
×
319
    swapchainCreateInfo.usageFlags  = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT; // Technically ignored with OpenGL
×
320
    swapchainCreateInfo.format      = selectColorSwapchainFormat(formats);
×
321
    swapchainCreateInfo.sampleCount = viewConfigViews[viewIndex].recommendedSwapchainSampleCount;
×
322
    swapchainCreateInfo.width       = viewConfigViews[viewIndex].recommendedImageRectWidth;
×
323
    swapchainCreateInfo.height      = viewConfigViews[viewIndex].recommendedImageRectHeight;
×
324
    swapchainCreateInfo.faceCount   = 1;
×
325
    swapchainCreateInfo.arraySize   = 1;
×
326
    swapchainCreateInfo.mipCount    = 1;
×
327
    checkLog(xrCreateSwapchain(m_handle, &swapchainCreateInfo, &colorSwapchain), "Failed to create color swapchain", m_instance);
×
328

329
    swapchainCreateInfo.createFlags = 0;
×
330
    swapchainCreateInfo.usageFlags  = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; // Technically ignored with OpenGL
×
331
    swapchainCreateInfo.format      = selectDepthSwapchainFormat(formats);
×
332
    swapchainCreateInfo.sampleCount = viewConfigViews[viewIndex].recommendedSwapchainSampleCount;
×
333
    swapchainCreateInfo.width       = viewConfigViews[viewIndex].recommendedImageRectWidth;
×
334
    swapchainCreateInfo.height      = viewConfigViews[viewIndex].recommendedImageRectHeight;
×
335
    swapchainCreateInfo.faceCount   = 1;
×
336
    swapchainCreateInfo.arraySize   = 1;
×
337
    swapchainCreateInfo.mipCount    = 1;
×
338
    checkLog(xrCreateSwapchain(m_handle, &swapchainCreateInfo, &depthSwapchain), "Failed to create depth swapchain", m_instance);
×
339

340
    createSwapchainImages(colorSwapchain, SwapchainType::COLOR);
×
341
    createSwapchainImages(depthSwapchain, SwapchainType::DEPTH);
×
342
  }
343

344
  Logger::debug("[XrSession] Created swapchains");
×
345
}
×
346

347
void XrSession::destroySwapchains() {
×
348
  ZoneScopedN("XrSession::destroySwapchains");
349

350
  Logger::debug("[XrSession] Destroying swapchains...");
×
351

352
  for (std::size_t swapchainIndex = 0; swapchainIndex < m_colorSwapchains.size(); ++swapchainIndex) {
×
353
    checkLog(xrDestroySwapchain(m_colorSwapchains[swapchainIndex]), "Failed to destroy color swapchain", m_instance);
×
354
    checkLog(xrDestroySwapchain(m_depthSwapchains[swapchainIndex]), "Failed to destroy depth swapchain", m_instance);
×
355
  }
356

357
  m_swapchainImages.clear();
×
358

359
  Logger::debug("[XrSession] Destroyed swapchains");
×
360
}
×
361

362
void XrSession::createSwapchainImages(XrSwapchain swapchain, SwapchainType swapchainType) {
×
363
  ZoneScopedN("XrSession::createSwapchainImages");
364

365
  const std::string typeStr = (swapchainType == SwapchainType::DEPTH ? "depth" : "color");
×
366

367
  Logger::debug("[XrSession] Creating " + typeStr + " swapchain images...");
×
368

369
  uint32_t swapchainImageCount {};
×
370
  checkLog(xrEnumerateSwapchainImages(swapchain, 0, &swapchainImageCount, nullptr),
×
371
           "Failed to get " + typeStr + " swapchain image count",
×
372
           m_instance);
373

374
  std::vector<XrSwapchainImageOpenGLKHR>& images = m_swapchainImages[swapchain];
×
375
  images.resize(swapchainImageCount, { XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR });
×
376
  checkLog(xrEnumerateSwapchainImages(swapchain, swapchainImageCount, &swapchainImageCount,
×
377
                                      reinterpret_cast<XrSwapchainImageBaseHeader*>(images.data())),
×
378
           "Failed to enumerate " + typeStr + " swapchain images",
×
379
           m_instance);
380

381
  Logger::debug("[XrSession] Created " + typeStr + " swapchain images");
×
382
}
×
383

384
void XrSession::createReferenceSpace() {
×
385
  ZoneScopedN("XrSession::createReferenceSpace");
386

387
  Logger::debug("[XrSession] Creating reference space...");
×
388

389
  XrReferenceSpaceCreateInfo referenceSpaceCreateInfo {};
×
390
  referenceSpaceCreateInfo.type                 = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
×
391
  referenceSpaceCreateInfo.referenceSpaceType   = XR_REFERENCE_SPACE_TYPE_LOCAL;
×
392
  referenceSpaceCreateInfo.poseInReferenceSpace = { XrQuaternionf{ 0.f, 0.f, 0.f, 1.f }, XrVector3f{ 0.f, 0.f, 0.f }};
×
393
  checkLog(xrCreateReferenceSpace(m_handle, &referenceSpaceCreateInfo, &m_localSpace), "Failed to create reference space", m_instance);
×
394

395
  Logger::debug("[XrSession] Created reference space");
×
396
}
×
397

398
void XrSession::destroyReferenceSpace() {
×
399
  Logger::debug("[XrSession] Destroying reference space...");
×
400
  checkLog(xrDestroySpace(m_localSpace), "Failed to destroy space", m_instance);
×
401
  Logger::debug("[XrSession] Destroyed reference space");
×
402
}
×
403

404
bool XrSession::renderLayer(RenderLayerInfo& layerInfo,
×
405
                            const std::vector<XrViewConfigurationView>& viewConfigViews,
406
                            unsigned int viewConfigType,
407
                            const ViewRenderFunc& viewRenderFunc) {
408
  ZoneScopedN("XrSession::renderLayer");
409

410
  std::vector<XrView> views(m_swapchainImages.size(), { XR_TYPE_VIEW });
×
411

412
  XrViewLocateInfo viewLocateInfo {};
×
413
  viewLocateInfo.type                  = XR_TYPE_VIEW_LOCATE_INFO;
×
414
  viewLocateInfo.viewConfigurationType = static_cast<XrViewConfigurationType>(viewConfigType);
×
415
  viewLocateInfo.displayTime           = layerInfo.predictedDisplayTime;
×
416
  viewLocateInfo.space                 = m_localSpace;
×
417
  XrViewState viewState {};
×
418
  viewState.type = XR_TYPE_VIEW_STATE;
×
419
  uint32_t viewCount {};
×
420
  if (xrLocateViews(m_handle, &viewLocateInfo, &viewState, static_cast<uint32_t>(views.size()), &viewCount, views.data()) != XR_SUCCESS) {
×
421
    Logger::error("[XrSession] Failed to locate views");
×
422
    return false;
×
423
  }
424

425
  // TODO: view state flags must be checked; see: https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrViewStateFlagBits.html#_description
426

427
  layerInfo.layerProjectionViews.resize(viewCount, { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW });
×
428

429
  for (uint32_t viewIndex = 0; viewIndex < viewCount; ++viewIndex) {
×
430
    const char* eyeStr = (viewCount == 1 ? "Single view"
×
431
                       : (viewIndex == 0 ? "Left eye"
×
432
                                         : "Right eye"));
433

434
    ZoneTransientN(cpuEyeZone, eyeStr, true);
435

436
    const XrSwapchain colorSwapchain = m_colorSwapchains[viewIndex];
×
437
    const XrSwapchain depthSwapchain = m_depthSwapchains[viewIndex];
×
438

439
    XrSwapchainImageAcquireInfo acquireInfo {};
×
440
    acquireInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO;
×
441
    uint32_t colorImageIndex {};
×
442
    uint32_t depthImageIndex {};
×
443
    checkLog(xrAcquireSwapchainImage(colorSwapchain, &acquireInfo, &colorImageIndex),
×
444
             "Failed to acquire image from the color swapchain",
445
             m_instance);
446
    checkLog(xrAcquireSwapchainImage(depthSwapchain, &acquireInfo, &depthImageIndex),
×
447
             "Failed to acquire image from the depth swapchain",
448
             m_instance);
449

450
    XrSwapchainImageWaitInfo waitInfo {};
×
451
    waitInfo.type    = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
×
452
    waitInfo.timeout = XR_INFINITE_DURATION;
×
453
    checkLog(xrWaitSwapchainImage(colorSwapchain, &waitInfo), "Failed to wait for image from the color swapchain", m_instance);
×
454
    checkLog(xrWaitSwapchainImage(depthSwapchain, &waitInfo), "Failed to wait for image from the depth swapchain", m_instance);
×
455

456
    const uint32_t width  = viewConfigViews[viewIndex].recommendedImageRectWidth;
×
457
    const uint32_t height = viewConfigViews[viewIndex].recommendedImageRectHeight;
×
458

459
    const XrView& currentView = views[viewIndex];
×
460

461
    XrCompositionLayerProjectionView& layerProjectionView = layerInfo.layerProjectionViews[viewIndex];
×
462
    layerProjectionView.type                      = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
×
463
    layerProjectionView.pose                      = currentView.pose;
×
464
    layerProjectionView.fov                       = currentView.fov;
×
465
    layerProjectionView.subImage.swapchain        = colorSwapchain;
×
466
    layerProjectionView.subImage.imageRect.offset = { 0, 0 };
×
467
    layerProjectionView.subImage.imageRect.extent = { static_cast<int32_t>(width), static_cast<int32_t>(height) };
×
468
    layerProjectionView.subImage.imageArrayIndex  = 0;  // Useful for multiview rendering
×
469

470
    TracyGpuZoneTransient(gpuEyeZone, eyeStr, true)
471

472
#if defined(RAZ_CONFIG_DEBUG)
473
    if (Renderer::checkVersion(4, 3))
×
474
      Renderer::pushDebugGroup(eyeStr);
×
475
#endif
476

477
    const auto& [colorBuffer, depthBuffer] = viewRenderFunc(Vec3f(currentView.pose.position.x, currentView.pose.position.y, currentView.pose.position.z),
×
478
                                                            Quaternionf(currentView.pose.orientation.w, currentView.pose.orientation.x,
×
479
                                                                        currentView.pose.orientation.y, currentView.pose.orientation.z),
×
480
                                                            ViewFov{ Radiansf(currentView.fov.angleRight), Radiansf(currentView.fov.angleLeft),
×
481
                                                                     Radiansf(currentView.fov.angleUp), Radiansf(currentView.fov.angleDown) });
×
482

483
    const uint32_t colorSwapchainImage = m_swapchainImages.find(colorSwapchain)->second[colorImageIndex].image;
×
484
    const uint32_t depthSwapchainImage = m_swapchainImages.find(depthSwapchain)->second[depthImageIndex].image;
×
485
    copyToSwapchains(colorBuffer, depthBuffer, colorSwapchainImage, depthSwapchainImage);
×
486

487
#if defined(RAZ_CONFIG_DEBUG)
488
    if (Renderer::checkVersion(4, 3))
×
489
      Renderer::popDebugGroup();
×
490
#endif
491

492
    XrSwapchainImageReleaseInfo releaseInfo {};
×
493
    releaseInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO;
×
494
    checkLog(xrReleaseSwapchainImage(colorSwapchain, &releaseInfo), "Failed to release image back to the color swapchain", m_instance);
×
495
    checkLog(xrReleaseSwapchainImage(depthSwapchain, &releaseInfo), "Failed to release image back to the depth swapchain", m_instance);
×
496
  }
497

498
  layerInfo.layerProjection.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT
×
499
                                       | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT; // Should be deprecated and ignored
500
  layerInfo.layerProjection.space      = m_localSpace;
×
501
  layerInfo.layerProjection.viewCount  = static_cast<uint32_t>(layerInfo.layerProjectionViews.size());
×
502
  layerInfo.layerProjection.views      = layerInfo.layerProjectionViews.data();
×
503

504
  return true;
×
505
}
×
506

507
void XrSession::copyToSwapchains(const Texture2D& colorBuffer, const Texture2D& depthBuffer, uint32_t colorSwapchainImage, uint32_t depthSwapchainImage) {
×
508
  ZoneScopedN("XrSession::copyToSwapchains");
509
  TracyGpuZone("XrSession::copyToSwapchains")
510

511
  m_swapchainCopyPass.getProgram().use();
×
512
  Renderer::activateTexture(0);
×
513
  colorBuffer.bind();
×
514
  Renderer::activateTexture(1);
×
515
  depthBuffer.bind();
×
516

517
  Renderer::bindFramebuffer(m_swapchainCopyPass.getFramebuffer().getIndex(), FramebufferType::DRAW_FRAMEBUFFER);
×
518
  Renderer::setFramebufferTexture2D(FramebufferAttachment::COLOR0, colorSwapchainImage, 0);
×
519
  Renderer::setFramebufferTexture2D(FramebufferAttachment::DEPTH, depthSwapchainImage, 0);
×
520
  Renderer::clear(MaskType::COLOR | MaskType::DEPTH | MaskType::STENCIL);
×
521

522
  Renderer::setDepthFunction(DepthStencilFunction::ALWAYS);
×
523
  m_swapchainCopyPass.execute();
×
524
  Renderer::setDepthFunction(DepthStencilFunction::LESS);
×
525
}
×
526

527
} // namespace Raz
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc