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

Razakhel / RaZ / 11821422553

13 Nov 2024 04:20PM UTC coverage: 74.45% (-0.03%) from 74.478%
11821422553

push

github

Razakhel
[XR/XrSession] Depth test always passes when copying to swapchains

- This allows the whole frame to be copied, not just fragments that have an actual depth
  - This also fixes cubemap rendering, which simply resulted in flickering without it

- The same is done for the default framebuffer (window) copy

1 of 5 new or added lines in 3 files covered. (20.0%)

3 existing lines in 2 files now uncovered.

8054 of 10818 relevant lines covered (74.45%)

1818.2 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

235
void 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)
×
242
    return;
×
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
}
×
279

280
XrSession::~XrSession() {
×
281
  if (m_handle == XR_NULL_HANDLE)
×
282
    return;
×
283

284
  Logger::debug("[XrSession] Destroying session...");
×
285

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

290
  Logger::debug("[XrSession] Destroyed session");
×
291
}
×
292

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

296
  Logger::debug("[XrSession] Creating swapchains...");
×
297

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

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

306
  m_colorSwapchains.resize(viewConfigViews.size());
×
307
  m_depthSwapchains.resize(viewConfigViews.size());
×
308
  m_swapchainImages.reserve(viewConfigViews.size());
×
309

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

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

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

338
    createSwapchainImages(colorSwapchain, SwapchainType::COLOR);
×
339
    createSwapchainImages(depthSwapchain, SwapchainType::DEPTH);
×
340
  }
341

342
  Logger::debug("[XrSession] Created swapchains");
×
343
}
×
344

345
void XrSession::destroySwapchains() {
×
346
  ZoneScopedN("XrSession::destroySwapchains");
347

348
  Logger::debug("[XrSession] Destroying swapchains...");
×
349

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

355
  m_swapchainImages.clear();
×
356

357
  Logger::debug("[XrSession] Destroyed swapchains");
×
358
}
×
359

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

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

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

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

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

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

382
void XrSession::createReferenceSpace() {
×
383
  ZoneScopedN("XrSession::createReferenceSpace");
384

385
  Logger::debug("[XrSession] Creating reference space...");
×
386

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

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

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

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

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

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

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

425
  layerInfo.layerProjectionViews.resize(viewCount, { XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW });
×
426

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

432
    ZoneTransientN(cpuEyeZone, eyeStr, true);
433

434
    const XrSwapchain colorSwapchain = m_colorSwapchains[viewIndex];
×
435
    const XrSwapchain depthSwapchain = m_depthSwapchains[viewIndex];
×
436

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

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

454
    const uint32_t width  = viewConfigViews[viewIndex].recommendedImageRectWidth;
×
455
    const uint32_t height = viewConfigViews[viewIndex].recommendedImageRectHeight;
×
456

457
    const XrView& currentView = views[viewIndex];
×
458

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

468
    TracyGpuZoneTransient(gpuEyeZone, eyeStr, true)
469

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

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

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

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

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

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

502
  return true;
×
503
}
×
504

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

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

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

NEW
520
  Renderer::setDepthFunction(DepthStencilFunction::ALWAYS);
×
521
  m_swapchainCopyPass.execute();
×
NEW
522
  Renderer::setDepthFunction(DepthStencilFunction::LESS);
×
UNCOV
523
}
×
524

525
} // 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