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

Razakhel / RaZ / 11805424802

12 Nov 2024 07:55PM UTC coverage: 74.798% (-4.7%) from 79.538%
11805424802

push

github

Razakhel
[Render/RenderSystem] Enabled XR multi-view rendering

- XR can be enabled in the RenderSystem; if it has been, the scene is rendered once per view each frame

15 of 65 new or added lines in 2 files covered. (23.08%)

1 existing line in 1 file now uncovered.

8055 of 10769 relevant lines covered (74.8%)

1826.46 hits per line

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

0.0
/src/RaZ/XR/XrSystem.cpp
1
#include "RaZ/Math/Vector.hpp"
2
#include "RaZ/Utils/Logger.hpp"
3
#include "RaZ/XR/XrContext.hpp"
4
#include "RaZ/XR/XrSystem.hpp"
5

6
#include "openxr/openxr.h"
7

8
#include <array>
9
#include <cassert>
10

11
namespace Raz {
12

13
namespace {
14

15
const char* getResultStr(XrInstance instance, XrResult result) {
×
16
  static std::array<char, XR_MAX_RESULT_STRING_SIZE> errorStr {};
17
  xrResultToString(instance, result, errorStr.data());
×
18
  return errorStr.data();
×
19
}
20

21
std::string getErrorStr(const std::string& errorMsg, XrResult result, XrInstance instance) {
×
22
  return "[XrSystem] " + errorMsg + ": " + getResultStr(instance, result) + " (" + std::to_string(result) + ')';
×
23
}
24

25
void checkLog(XrResult result, const std::string& errorMsg, XrInstance instance) {
×
26
  if (XR_SUCCEEDED(result))
×
27
    return;
×
28

29
  Logger::error(getErrorStr(errorMsg, result, instance));
×
30
}
31

32
bool pollNextEvent(XrInstance instance, XrEventDataBuffer& eventData) {
×
33
  eventData      = {};
×
34
  eventData.type = XR_TYPE_EVENT_DATA_BUFFER;
×
35

36
  return (xrPollEvent(instance, &eventData) == XR_SUCCESS);
×
37
}
38

39
void processEventData(const XrEventDataEventsLost& eventsLost) {
×
40
  Logger::info("[XrSystem] " + std::to_string(eventsLost.lostEventCount) + " events lost");
×
41
}
×
42

43
void processEventData(const XrEventDataInstanceLossPending& instanceLossPending) {
×
44
  // After the period of time specified by lossTime, the application can try recreating an instance again
45
  // See: https://registry.khronos.org/OpenXR/specs/1.0/man/html/XrEventDataInstanceLossPending.html#_description
46
  Logger::info("[XrSystem] Instance loss pending at: " + std::to_string(instanceLossPending.lossTime));
×
47
}
×
48

49
void processEventData(const XrEventDataInteractionProfileChanged& interactionProfileChanged, ::XrSession session) {
×
50
  Logger::info("[XrSystem] Interaction profile changed for "
×
51
             + std::string(interactionProfileChanged.session != session ? "unknown" : "current")
×
52
             + " session");
×
53
}
×
54

55
void processEventData(const XrEventDataReferenceSpaceChangePending& referenceSpaceChangePending, ::XrSession session) {
×
56
  Logger::info("[XrSystem] Reference space changed pending for "
×
57
             + std::string(referenceSpaceChangePending.session != session ? "unknown" : "current")
×
58
             + " session");
×
59
}
×
60

61
} // namespace
62

63
XrSystem::XrSystem(const std::string& appName) : m_context(appName), m_session(m_context) {
×
64
  recoverViewConfigurations();
×
65
  m_session.createSwapchains(m_viewConfigViews);
×
66
  recoverEnvironmentBlendModes();
×
67
}
×
68

69
bool XrSystem::update(const FrameTimeInfo&) {
×
70
  XrEventDataBuffer eventData {};
×
71

72
  while (pollNextEvent(m_context.m_instance, eventData)) {
×
73
    switch (eventData.type) {
×
74
      case XR_TYPE_EVENT_DATA_EVENTS_LOST:
×
75
        processEventData(*reinterpret_cast<XrEventDataEventsLost*>(&eventData));
×
76
        break;
×
77

78
      case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING:
×
79
        processEventData(*reinterpret_cast<XrEventDataInstanceLossPending*>(&eventData));
×
80
        m_session.m_isRunning = false;
×
81
        return false;
×
82

83
      case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
×
84
        processEventData(*reinterpret_cast<XrEventDataInteractionProfileChanged*>(&eventData), m_session.m_handle);
×
85
        break;
×
86

87
      case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
×
88
        processEventData(*reinterpret_cast<XrEventDataReferenceSpaceChangePending*>(&eventData), m_session.m_handle);
×
89
        break;
×
90

91
      case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED:
×
92
        processSessionStateChanged(*reinterpret_cast<XrEventDataSessionStateChanged*>(&eventData));
×
93
        break;
×
94

95
      default:
×
96
        break;
×
97
    }
98
  }
99

100
  return true;
×
101
}
102

103
XrSystem::~XrSystem() = default;
×
104

NEW
105
Vec2u XrSystem::recoverOptimalViewSize() const {
×
NEW
106
  assert("[XrSystem] View configuration views must be recovered before getting the optimal view size" && !m_viewConfigViews.empty());
×
107

NEW
108
  Vec2u optimalViewSize(m_viewConfigViews.front().recommendedImageRectWidth, m_viewConfigViews.front().recommendedImageRectHeight);
×
109

NEW
110
  if (m_viewConfigViews.size() > 1) {
×
NEW
111
    for (const XrViewConfigurationView& viewConfigView : m_viewConfigViews) {
×
NEW
112
      if (viewConfigView.recommendedImageRectWidth != optimalViewSize.x() || viewConfigView.recommendedImageRectHeight != optimalViewSize.y())
×
NEW
113
        Logger::warn("[XrSystem] The optimal configuration view size is not the same for all views; rendering may be altered");
×
114
    }
115
  }
116

NEW
117
  return optimalViewSize;
×
118
}
119

NEW
120
void XrSystem::renderFrame(const ViewRenderFunc& viewRenderFunc) {
×
NEW
121
  m_session.renderFrame(m_viewConfigViews, m_viewConfigType, m_environmentBlendMode, viewRenderFunc);
×
NEW
122
}
×
123

124
void XrSystem::recoverViewConfigurations() {
×
125
  uint32_t viewConfigCount {};
×
126
  checkLog(xrEnumerateViewConfigurations(m_context.m_instance, m_context.m_systemId, 0, &viewConfigCount, nullptr),
×
127
           "Failed to get view configuration count",
128
           m_context.m_instance);
129
  m_viewConfigTypes.resize(viewConfigCount);
×
130
  checkLog(xrEnumerateViewConfigurations(m_context.m_instance, m_context.m_systemId, viewConfigCount, &viewConfigCount,
×
131
                                         reinterpret_cast<XrViewConfigurationType*>(m_viewConfigTypes.data())),
×
132
           "Failed to enumerate view configurations",
133
           m_context.m_instance);
134

135
  for (const XrViewConfigurationType viewConfigType : { XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO }) {
×
136
    if (std::find(m_viewConfigTypes.cbegin(), m_viewConfigTypes.cend(), viewConfigType) == m_viewConfigTypes.cend())
×
137
      continue;
×
138

139
    m_viewConfigType = viewConfigType;
×
140
    break;
×
141
  }
142

143
  if (m_viewConfigType == 0) {
×
144
    Logger::warn("[XrSystem] Failed to find a view configuration type; defaulting to XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO");
×
145
    m_viewConfigType = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
×
146
  }
147

148
  uint32_t viewConfigViewCount {};
×
149
  checkLog(xrEnumerateViewConfigurationViews(m_context.m_instance, m_context.m_systemId, static_cast<XrViewConfigurationType>(m_viewConfigType),
×
150
                                             0, &viewConfigViewCount, nullptr),
151
           "Failed to get view configuration view count",
152
           m_context.m_instance);
153
  m_viewConfigViews.resize(viewConfigViewCount, { XR_TYPE_VIEW_CONFIGURATION_VIEW });
×
154
  checkLog(xrEnumerateViewConfigurationViews(m_context.m_instance, m_context.m_systemId, static_cast<XrViewConfigurationType>(m_viewConfigType),
×
155
                                             viewConfigViewCount, &viewConfigViewCount,
156
                                             m_viewConfigViews.data()),
157
           "Failed to enumerate view configuration views",
158
           m_context.m_instance);
159

160
#if !defined(NDEBUG) || defined(RAZ_FORCE_DEBUG_LOG)
161
  {
162
    std::string viewConfigViewsMsg = "[XrSystem] View configuration views:";
×
163
    for (const XrViewConfigurationView& viewConfigView : m_viewConfigViews) {
×
164
      viewConfigViewsMsg += "\n    View:"
165
                            "\n        Recom. image rect width:       " + std::to_string(viewConfigView.recommendedImageRectWidth)
×
166
                          + "\n        Max. image rect width:         " + std::to_string(viewConfigView.maxImageRectWidth)
×
167
                          + "\n        Recom. image rect height:      " + std::to_string(viewConfigView.recommendedImageRectHeight)
×
168
                          + "\n        Max. image rect height:        " + std::to_string(viewConfigView.maxImageRectHeight)
×
169
                          + "\n        Recom. swapchain sample count: " + std::to_string(viewConfigView.recommendedSwapchainSampleCount)
×
170
                          + "\n        Max. swapchain sample count:   " + std::to_string(viewConfigView.maxSwapchainSampleCount);
×
171
    }
172
    Logger::debug(viewConfigViewsMsg);
×
173
  }
×
174
#endif
175
}
×
176

177
void XrSystem::recoverEnvironmentBlendModes() {
×
178
  uint32_t environmentBlendModeCount {};
×
179
  checkLog(xrEnumerateEnvironmentBlendModes(m_context.m_instance, m_context.m_systemId, static_cast<XrViewConfigurationType>(m_viewConfigType),
×
180
                                            0, &environmentBlendModeCount, nullptr),
181
           "Failed to get environment blend mode count",
182
           m_context.m_instance);
183
  m_environmentBlendModes.resize(environmentBlendModeCount);
×
184
  checkLog(xrEnumerateEnvironmentBlendModes(m_context.m_instance, m_context.m_systemId, static_cast<XrViewConfigurationType>(m_viewConfigType),
×
185
                                            environmentBlendModeCount, &environmentBlendModeCount,
186
                                            reinterpret_cast<XrEnvironmentBlendMode*>(m_environmentBlendModes.data())),
×
187
           "Failed to enumerate environment blend modes",
188
           m_context.m_instance);
189

190
  for (const XrEnvironmentBlendMode environmentBlendMode : { XR_ENVIRONMENT_BLEND_MODE_OPAQUE, XR_ENVIRONMENT_BLEND_MODE_ADDITIVE }) {
×
191
    if (std::find(m_environmentBlendModes.cbegin(), m_environmentBlendModes.cend(), environmentBlendMode) == m_environmentBlendModes.cend())
×
192
      continue;
×
193

194
    m_environmentBlendMode = environmentBlendMode;
×
195
    break;
×
196
  }
197

198
  if (m_environmentBlendMode == 0) {
×
199
    Logger::warn("Failed to find a compatible blend mode; defaulting to XR_ENVIRONMENT_BLEND_MODE_OPAQUE");
×
200
    m_environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
×
201
  }
202
}
×
203

204
bool XrSystem::processSessionStateChanged(const XrEventDataSessionStateChanged& sessionStateChanged) {
×
205
  if (sessionStateChanged.session != m_session.m_handle) {
×
206
    Logger::info("[XrSystem] Data session state changed for unknown session");
×
207
    return true;
×
208
  }
209

210
  switch (sessionStateChanged.state) {
×
211
    case XR_SESSION_STATE_READY:
×
212
      m_session.begin(m_viewConfigType);
×
213
      m_session.m_isRunning = true;
×
214
      break;
×
215

216
    case XR_SESSION_STATE_STOPPING:
×
217
      m_session.end();
×
218
      m_session.m_isRunning = false;
×
219
      break;
×
220

221
    case XR_SESSION_STATE_LOSS_PENDING:
×
222
      // TODO: "It's possible to try to reestablish an XrInstance and XrSession"
223
      m_session.m_isRunning = false;
×
224
      return false;
×
225

226
    case XR_SESSION_STATE_EXITING:
×
227
      m_session.m_isRunning = false;
×
228
      return false;
×
229

230
    default:
×
231
      break;
×
232
  }
233

234
  m_session.m_state = sessionStateChanged.state;
×
235

236
  return true;
×
237
}
238

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