Blender V4.3
GHOST_XrGraphicsBinding.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2020-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <algorithm>
10#include <list>
11#include <sstream>
12
13#if defined(WITH_GHOST_X11)
14# include "GHOST_ContextEGL.hh"
15# include "GHOST_ContextGLX.hh"
16# include "GHOST_SystemX11.hh"
17#endif
18#if defined(WITH_GHOST_WAYLAND)
19# include "GHOST_ContextEGL.hh"
20# include "GHOST_SystemWayland.hh"
21#endif
22#if defined(WIN32)
23# include "GHOST_ContextD3D.hh"
24# include "GHOST_ContextWGL.hh"
25# include "GHOST_SystemWin32.hh"
26#endif
27#include "GHOST_C-api.h"
28#include "GHOST_XrException.hh"
29#include "GHOST_Xr_intern.hh"
30
32
33static std::optional<int64_t> choose_swapchain_format_from_candidates(
34 const std::vector<int64_t> &gpu_binding_formats, const std::vector<int64_t> &runtime_formats)
35{
36 if (gpu_binding_formats.empty()) {
37 return std::nullopt;
38 }
39
40 auto res = std::find_first_of(gpu_binding_formats.begin(),
41 gpu_binding_formats.end(),
42 runtime_formats.begin(),
43 runtime_formats.end());
44 if (res == gpu_binding_formats.end()) {
45 return std::nullopt;
46 }
47
48 return *res;
49}
50
52 public:
54 {
55 if (m_fbo != 0) {
56 glDeleteFramebuffers(1, &m_fbo);
57 }
58 }
59
61 XrInstance instance,
62 XrSystemId system_id,
63 std::string *r_requirement_info) const override
64 {
65 int gl_major_version, gl_minor_version;
66#if defined(WIN32)
67 GHOST_ContextWGL &ctx_gl = static_cast<GHOST_ContextWGL &>(ghost_ctx);
68 gl_major_version = ctx_gl.m_contextMajorVersion;
69 gl_minor_version = ctx_gl.m_contextMinorVersion;
70#elif defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND)
71 if (dynamic_cast<GHOST_ContextEGL *>(&ghost_ctx)) {
72 GHOST_ContextEGL &ctx_gl = static_cast<GHOST_ContextEGL &>(ghost_ctx);
73 gl_major_version = ctx_gl.m_contextMajorVersion;
74 gl_minor_version = ctx_gl.m_contextMinorVersion;
75 }
76# if defined(WITH_GHOST_X11)
77 else {
78 GHOST_ContextGLX &ctx_gl = static_cast<GHOST_ContextGLX &>(ghost_ctx);
79 gl_major_version = ctx_gl.m_contextMajorVersion;
80 gl_minor_version = ctx_gl.m_contextMinorVersion;
81 }
82# endif
83#endif
84 static PFN_xrGetOpenGLGraphicsRequirementsKHR s_xrGetOpenGLGraphicsRequirementsKHR_fn =
85 nullptr;
86 // static XrInstance s_instance = XR_NULL_HANDLE;
87 XrGraphicsRequirementsOpenGLKHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR};
88 const XrVersion gl_version = XR_MAKE_VERSION(gl_major_version, gl_minor_version, 0);
89
90 /* Although it would seem reasonable that the PROC address would not change if the instance was
91 * the same, in testing, repeated calls to #xrGetInstanceProcAddress() with the same instance
92 * can still result in changes so the workaround is to simply set the function pointer every
93 * time (trivializing its 'static' designation). */
94 // if (instance != s_instance) {
95 // s_instance = instance;
96 s_xrGetOpenGLGraphicsRequirementsKHR_fn = nullptr;
97 //}
98 if (!s_xrGetOpenGLGraphicsRequirementsKHR_fn &&
99 XR_FAILED(
100 xrGetInstanceProcAddr(instance,
101 "xrGetOpenGLGraphicsRequirementsKHR",
102 (PFN_xrVoidFunction *)&s_xrGetOpenGLGraphicsRequirementsKHR_fn)))
103 {
104 s_xrGetOpenGLGraphicsRequirementsKHR_fn = nullptr;
105 return false;
106 }
107
108 s_xrGetOpenGLGraphicsRequirementsKHR_fn(instance, system_id, &gpu_requirements);
109
110 if (r_requirement_info) {
111 std::ostringstream strstream;
112 strstream << "Min OpenGL version "
113 << XR_VERSION_MAJOR(gpu_requirements.minApiVersionSupported) << "."
114 << XR_VERSION_MINOR(gpu_requirements.minApiVersionSupported) << std::endl;
115 strstream << "Max OpenGL version "
116 << XR_VERSION_MAJOR(gpu_requirements.maxApiVersionSupported) << "."
117 << XR_VERSION_MINOR(gpu_requirements.maxApiVersionSupported) << std::endl;
118
119 *r_requirement_info = strstream.str();
120 }
121
122 return (gl_version >= gpu_requirements.minApiVersionSupported) &&
123 (gl_version <= gpu_requirements.maxApiVersionSupported);
124 }
125
126 void initFromGhostContext(GHOST_Context &ghost_ctx) override
127 {
128#if defined(WITH_GHOST_X11) || defined(WITH_GHOST_WAYLAND)
129 /* WAYLAND/X11 may be dynamically selected at load time but both may also be
130 * supported at compile time individually.
131 * Without `is_ctx_egl` & `is_wayland` preprocessor checks become an unmanageable soup. */
132 const bool is_ctx_egl = dynamic_cast<GHOST_ContextEGL *>(&ghost_ctx) != nullptr;
133 if (is_ctx_egl) {
134 GHOST_ContextEGL &ctx_egl = static_cast<GHOST_ContextEGL &>(ghost_ctx);
135 const bool is_wayland = (
136# if defined(WITH_GHOST_WAYLAND)
137 dynamic_cast<const GHOST_SystemWayland *const>(ctx_egl.m_system) != nullptr
138# else
139 false
140# endif
141 );
142
143 if (is_wayland) {
144# if defined(WITH_GHOST_WAYLAND)
145 /* #GHOST_SystemWayland */
146 oxr_binding.wl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR;
147 oxr_binding.wl.display = (wl_display *)ctx_egl.m_nativeDisplay;
148# else
149 GHOST_ASSERT(false, "Unexpected State: logical error, unreachable!");
150# endif /* !WITH_GHOST_WAYLAND */
151 }
152 else { /* `!is_wayland` */
153# if defined(WITH_GHOST_X11)
154 /* #GHOST_SystemX11. */
155 oxr_binding.egl.type = XR_TYPE_GRAPHICS_BINDING_EGL_MNDX;
156# if XR_CURRENT_API_VERSION >= XR_MAKE_VERSION(1, 0, 29)
157 oxr_binding.egl.getProcAddress = reinterpret_cast<PFN_xrEglGetProcAddressMNDX>(
158 eglGetProcAddress);
159# else
160 oxr_binding.egl.getProcAddress = reinterpret_cast<PFNEGLGETPROCADDRESSPROC>(
161 eglGetProcAddress);
162# endif
163 oxr_binding.egl.display = ctx_egl.getDisplay();
164 oxr_binding.egl.config = ctx_egl.getConfig();
165 oxr_binding.egl.context = ctx_egl.getContext();
166# else
167 GHOST_ASSERT(false, "Unexpected State: built with only WAYLAND and no System found!");
168# endif /* !WITH_GHOST_X11 */
169 }
170 }
171 else { /* `!is_ctx_egl` */
172# if defined(WITH_GHOST_X11)
173 GHOST_ContextGLX &ctx_glx = static_cast<GHOST_ContextGLX &>(ghost_ctx);
174 XVisualInfo *visual_info = glXGetVisualFromFBConfig(ctx_glx.m_display, ctx_glx.m_fbconfig);
175
176 oxr_binding.glx.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR;
177 oxr_binding.glx.xDisplay = ctx_glx.m_display;
178 oxr_binding.glx.glxFBConfig = ctx_glx.m_fbconfig;
179 oxr_binding.glx.glxDrawable = ctx_glx.m_window;
180 oxr_binding.glx.glxContext = ctx_glx.m_context;
181 oxr_binding.glx.visualid = visual_info->visualid;
182
183 XFree(visual_info);
184# else
185 GHOST_ASSERT(false, "Unexpected State: built without X11 and no EGL context is available!");
186# endif /* !WITH_GHOST_X11 */
187 }
188#elif defined(WIN32)
189 GHOST_ContextWGL &ctx_wgl = static_cast<GHOST_ContextWGL &>(ghost_ctx);
190
191 oxr_binding.wgl.type = XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR;
192 oxr_binding.wgl.hDC = ctx_wgl.m_hDC;
193 oxr_binding.wgl.hGLRC = ctx_wgl.m_hGLRC;
194#endif /* WIN32 */
195
196 /* Generate a frame-buffer to use for blitting into the texture. */
197 glGenFramebuffers(1, &m_fbo);
198 }
199
200 std::optional<int64_t> chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
201 GHOST_TXrSwapchainFormat &r_format,
202 bool &r_is_srgb_format) const override
203 {
204 std::vector<int64_t> gpu_binding_formats = {
205#if 0 /* RGB10A2, RGBA16 don't seem to work with Oculus head-sets, \
206 * so move them after RGBA16F for the time being. */
207 GL_RGB10_A2,
208 GL_RGBA16,
209#endif
210 GL_RGBA16F,
211#if 1
212 GL_RGB10_A2,
213 GL_RGBA16,
214#endif
215 GL_RGBA8,
216 GL_SRGB8_ALPHA8,
217 };
218
219 std::optional result = choose_swapchain_format_from_candidates(gpu_binding_formats,
220 runtime_formats);
221 if (result) {
222 switch (*result) {
223 case GL_RGB10_A2:
224 r_format = GHOST_kXrSwapchainFormatRGB10_A2;
225 break;
226 case GL_RGBA16:
227 r_format = GHOST_kXrSwapchainFormatRGBA16;
228 break;
229 case GL_RGBA16F:
230 r_format = GHOST_kXrSwapchainFormatRGBA16F;
231 break;
232 case GL_RGBA8:
233 case GL_SRGB8_ALPHA8:
234 r_format = GHOST_kXrSwapchainFormatRGBA8;
235 break;
236 }
237 r_is_srgb_format = (*result == GL_SRGB8_ALPHA8);
238 }
239 else {
240 r_format = GHOST_kXrSwapchainFormatRGBA8;
241 r_is_srgb_format = false;
242 }
243
244 return result;
245 }
246
247 std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
248 {
249 std::vector<XrSwapchainImageOpenGLKHR> ogl_images(image_count);
250 std::vector<XrSwapchainImageBaseHeader *> base_images;
251
252 /* Need to return vector of base header pointers, so of a different type. Need to build a new
253 * list with this type, and keep the initial one alive. */
254 for (XrSwapchainImageOpenGLKHR &image : ogl_images) {
255 image.type = XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR;
256 base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
257 }
258
259 /* Keep alive. */
260 m_image_cache.push_back(std::move(ogl_images));
261
262 return base_images;
263 }
264
265 void submitToSwapchainImage(XrSwapchainImageBaseHeader &swapchain_image,
266 const GHOST_XrDrawViewInfo &draw_info) override
267 {
268 XrSwapchainImageOpenGLKHR &ogl_swapchain_image = reinterpret_cast<XrSwapchainImageOpenGLKHR &>(
269 swapchain_image);
270
271 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo);
272
273 glFramebufferTexture2D(
274 GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ogl_swapchain_image.image, 0);
275
276 glBlitFramebuffer(draw_info.ofsx,
277 draw_info.ofsy,
278 draw_info.ofsx + draw_info.width,
279 draw_info.ofsy + draw_info.height,
280 draw_info.ofsx,
281 draw_info.ofsy,
282 draw_info.ofsx + draw_info.width,
283 draw_info.ofsy + draw_info.height,
284 GL_COLOR_BUFFER_BIT,
285 GL_LINEAR);
286
287 glBindFramebuffer(GL_FRAMEBUFFER, 0);
288 }
289
290 bool needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const override
291 {
292 return ghost_ctx.isUpsideDown();
293 }
294
295 private:
296 std::list<std::vector<XrSwapchainImageOpenGLKHR>> m_image_cache;
297 GLuint m_fbo = 0;
298};
299
300#ifdef WIN32
301static void ghost_format_to_dx_format(GHOST_TXrSwapchainFormat ghost_format,
302 bool expects_srgb_buffer,
303 DXGI_FORMAT &r_dx_format)
304{
305 r_dx_format = DXGI_FORMAT_UNKNOWN;
306
307 switch (ghost_format) {
308 case GHOST_kXrSwapchainFormatRGBA8:
309 r_dx_format = expects_srgb_buffer ? DXGI_FORMAT_R8G8B8A8_UNORM_SRGB :
310 DXGI_FORMAT_R8G8B8A8_UNORM;
311 break;
312 case GHOST_kXrSwapchainFormatRGBA16:
313 r_dx_format = DXGI_FORMAT_R16G16B16A16_UNORM;
314 break;
315 case GHOST_kXrSwapchainFormatRGBA16F:
316 r_dx_format = DXGI_FORMAT_R16G16B16A16_FLOAT;
317 break;
318 case GHOST_kXrSwapchainFormatRGB10_A2:
319 r_dx_format = DXGI_FORMAT_R10G10B10A2_UNORM;
320 break;
321 }
322
323 if (r_dx_format == DXGI_FORMAT_UNKNOWN) {
324 throw GHOST_XrException("No supported DirectX swapchain format found.");
325 }
326}
327
328class GHOST_XrGraphicsBindingD3D : public GHOST_IXrGraphicsBinding {
329 public:
330 GHOST_XrGraphicsBindingD3D(GHOST_Context &ghost_ctx)
331 : GHOST_IXrGraphicsBinding(), m_ghost_wgl_ctx(static_cast<GHOST_ContextWGL &>(ghost_ctx))
332 {
334 }
335 ~GHOST_XrGraphicsBindingD3D()
336 {
337 if (m_shared_resource) {
338 m_ghost_d3d_ctx->disposeSharedOpenGLResource(m_shared_resource);
339 }
340 if (m_ghost_d3d_ctx) {
342 }
343 }
344
346 GHOST_Context & /*ghost_ctx*/, /* Remember: This is the OpenGL context! */
347 XrInstance instance,
348 XrSystemId system_id,
349 std::string *r_requirement_info) const override
350 {
351 static PFN_xrGetD3D11GraphicsRequirementsKHR s_xrGetD3D11GraphicsRequirementsKHR_fn = nullptr;
352 // static XrInstance s_instance = XR_NULL_HANDLE;
353 XrGraphicsRequirementsD3D11KHR gpu_requirements = {XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR};
354
355 /* Although it would seem reasonable that the PROC address would not change if the instance was
356 * the same, in testing, repeated calls to #xrGetInstanceProcAddress() with the same instance
357 * can still result in changes so the workaround is to simply set the function pointer every
358 * time (trivializing its 'static' designation). */
359 // if (instance != s_instance) {
360 // s_instance = instance;
361 s_xrGetD3D11GraphicsRequirementsKHR_fn = nullptr;
362 //}
363 if (!s_xrGetD3D11GraphicsRequirementsKHR_fn &&
364 XR_FAILED(
365 xrGetInstanceProcAddr(instance,
366 "xrGetD3D11GraphicsRequirementsKHR",
367 (PFN_xrVoidFunction *)&s_xrGetD3D11GraphicsRequirementsKHR_fn)))
368 {
369 s_xrGetD3D11GraphicsRequirementsKHR_fn = nullptr;
370 return false;
371 }
372
373 s_xrGetD3D11GraphicsRequirementsKHR_fn(instance, system_id, &gpu_requirements);
374
375 if (r_requirement_info) {
376 std::ostringstream strstream;
377 strstream << "Minimum DirectX 11 Feature Level " << gpu_requirements.minFeatureLevel
378 << std::endl;
379
380 *r_requirement_info = strstream.str();
381 }
382
383 return m_ghost_d3d_ctx->m_device->GetFeatureLevel() >= gpu_requirements.minFeatureLevel;
384 }
385
387 GHOST_Context & /*ghost_ctx*/ /* Remember: This is the OpenGL context! */
388 ) override
389 {
390 oxr_binding.d3d11.type = XR_TYPE_GRAPHICS_BINDING_D3D11_KHR;
391 oxr_binding.d3d11.device = m_ghost_d3d_ctx->m_device;
392 }
393
394 std::optional<int64_t> chooseSwapchainFormat(const std::vector<int64_t> &runtime_formats,
395 GHOST_TXrSwapchainFormat &r_format,
396 bool &r_is_srgb_format) const override
397 {
398 std::vector<int64_t> gpu_binding_formats = {
399# if 0 /* RGB10A2, RGBA16 don't seem to work with Oculus head-sets, \
400 * so move them after RGBA16F for the time being. */
401 DXGI_FORMAT_R10G10B10A2_UNORM,
402 DXGI_FORMAT_R16G16B16A16_UNORM,
403# endif
404 DXGI_FORMAT_R16G16B16A16_FLOAT,
405# if 1
406 DXGI_FORMAT_R10G10B10A2_UNORM,
407 DXGI_FORMAT_R16G16B16A16_UNORM,
408# endif
409 DXGI_FORMAT_R8G8B8A8_UNORM,
410 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
411 };
412
413 std::optional result = choose_swapchain_format_from_candidates(gpu_binding_formats,
414 runtime_formats);
415 if (result) {
416 switch (*result) {
417 case DXGI_FORMAT_R10G10B10A2_UNORM:
418 r_format = GHOST_kXrSwapchainFormatRGB10_A2;
419 break;
420 case DXGI_FORMAT_R16G16B16A16_UNORM:
421 r_format = GHOST_kXrSwapchainFormatRGBA16;
422 break;
423 case DXGI_FORMAT_R16G16B16A16_FLOAT:
424 r_format = GHOST_kXrSwapchainFormatRGBA16F;
425 break;
426 case DXGI_FORMAT_R8G8B8A8_UNORM:
427 case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
428 r_format = GHOST_kXrSwapchainFormatRGBA8;
429 break;
430 }
431 r_is_srgb_format = (*result == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
432 }
433 else {
434 r_format = GHOST_kXrSwapchainFormatRGBA8;
435 r_is_srgb_format = false;
436 }
437
438 return result;
439 }
440
441 std::vector<XrSwapchainImageBaseHeader *> createSwapchainImages(uint32_t image_count) override
442 {
443 std::vector<XrSwapchainImageD3D11KHR> d3d_images(image_count);
444 std::vector<XrSwapchainImageBaseHeader *> base_images;
445
446 /* Need to return vector of base header pointers, so of a different type. Need to build a new
447 * list with this type, and keep the initial one alive. */
448 for (XrSwapchainImageD3D11KHR &image : d3d_images) {
449 image.type = XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR;
450 base_images.push_back(reinterpret_cast<XrSwapchainImageBaseHeader *>(&image));
451 }
452
453 /* Keep alive. */
454 m_image_cache.push_back(std::move(d3d_images));
455
456 return base_images;
457 }
458
459 void submitToSwapchainImage(XrSwapchainImageBaseHeader &swapchain_image,
460 const GHOST_XrDrawViewInfo &draw_info) override
461 {
462 XrSwapchainImageD3D11KHR &d3d_swapchain_image = reinterpret_cast<XrSwapchainImageD3D11KHR &>(
463 swapchain_image);
464
465# if 0
466 /* Ideally we'd just create a render target view for the OpenXR swap-chain image texture and
467 * blit from the OpenGL context into it. The NV_DX_interop extension doesn't want to work with
468 * this though. At least not with OPTIMUS hardware. See:
469 * https://github.com/mpv-player/mpv/issues/2949#issuecomment-197262807.
470 */
471
472 ID3D11RenderTargetView *rtv;
473 CD3D11_RENDER_TARGET_VIEW_DESC rtv_desc(D3D11_RTV_DIMENSION_TEXTURE2D,
474 DXGI_FORMAT_R8G8B8A8_UNORM);
475
476 m_ghost_ctx->m_device->CreateRenderTargetView(d3d_swapchain_image.texture, &rtv_desc, &rtv);
477 if (!m_shared_resource) {
478 DXGI_FORMAT format;
479 ghost_format_to_dx_format(draw_info.swapchain_format, draw_info.expects_srgb_buffer, format);
480 m_shared_resource = m_ghost_ctx->createSharedOpenGLResource(
481 draw_info.width, draw_info.height, format, rtv);
482 }
483 m_ghost_ctx->blitFromOpenGLContext(m_shared_resource, draw_info.width, draw_info.height);
484# else
485 if (!m_shared_resource) {
486 DXGI_FORMAT format;
487 ghost_format_to_dx_format(draw_info.swapchain_format, draw_info.expects_srgb_buffer, format);
488 m_shared_resource = m_ghost_d3d_ctx->createSharedOpenGLResource(
489 draw_info.width, draw_info.height, format);
490 }
491 m_ghost_d3d_ctx->blitFromOpenGLContext(m_shared_resource, draw_info.width, draw_info.height);
492
493 m_ghost_d3d_ctx->m_device_ctx->OMSetRenderTargets(0, nullptr, nullptr);
494 m_ghost_d3d_ctx->m_device_ctx->CopyResource(
495 d3d_swapchain_image.texture, m_ghost_d3d_ctx->getSharedTexture2D(m_shared_resource));
496# endif
497 }
498
500 {
501 return m_ghost_d3d_ctx->isUpsideDown();
502 }
503
504 private:
506 GHOST_ContextWGL &m_ghost_wgl_ctx;
508 GHOST_ContextD3D *m_ghost_d3d_ctx = nullptr;
510 GHOST_SharedOpenGLResource *m_shared_resource = nullptr;
511
512 std::list<std::vector<XrSwapchainImageD3D11KHR>> m_image_cache;
513};
514#endif // WIN32
515
516std::unique_ptr<GHOST_IXrGraphicsBinding> GHOST_XrGraphicsBindingCreateFromType(
517 GHOST_TXrGraphicsBinding type, GHOST_Context &context)
518{
519 switch (type) {
520 case GHOST_kXrGraphicsOpenGL:
521 return std::make_unique<GHOST_XrGraphicsBindingOpenGL>();
522#ifdef WIN32
523 case GHOST_kXrGraphicsD3D11:
524 return std::make_unique<GHOST_XrGraphicsBindingD3D>(context);
525#endif
526 default:
527 return nullptr;
528 }
529
530 (void)context; /* Might be unused. */
531}
GHOST C-API function and type declarations.
#define wl_display
#define GHOST_ASSERT(x, info)
static std::optional< int64_t > choose_swapchain_format_from_candidates(const std::vector< int64_t > &gpu_binding_formats, const std::vector< int64_t > &runtime_formats)
std::unique_ptr< GHOST_IXrGraphicsBinding > GHOST_XrGraphicsBindingCreateFromType(GHOST_TXrGraphicsBinding type, GHOST_Context &context)
EGLConfig getConfig() const
EGLDisplay getDisplay() const
EGLContext getContext() const
virtual bool isUpsideDown() const
union GHOST_IXrGraphicsBinding::@1476 oxr_binding
virtual bool needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const =0
virtual std::vector< XrSwapchainImageBaseHeader * > createSwapchainImages(uint32_t image_count)=0
virtual bool checkVersionRequirements(class GHOST_Context &ghost_ctx, XrInstance instance, XrSystemId system_id, std::string *r_requirement_info) const =0
virtual std::optional< int64_t > chooseSwapchainFormat(const std::vector< int64_t > &runtime_formats, GHOST_TXrSwapchainFormat &r_format, bool &r_is_rgb_format) const =0
virtual void initFromGhostContext(class GHOST_Context &ghost_ctx)=0
virtual void submitToSwapchainImage(XrSwapchainImageBaseHeader &swapchain_image, const GHOST_XrDrawViewInfo &draw_info)=0
static GHOST_ContextD3D * createOffscreenContextD3D()
static GHOST_TSuccess disposeContextD3D(GHOST_ContextD3D *context)
bool needsUpsideDownDrawing(GHOST_Context &ghost_ctx) const override
std::optional< int64_t > chooseSwapchainFormat(const std::vector< int64_t > &runtime_formats, GHOST_TXrSwapchainFormat &r_format, bool &r_is_srgb_format) const override
void initFromGhostContext(GHOST_Context &ghost_ctx) override
bool checkVersionRequirements(GHOST_Context &ghost_ctx, XrInstance instance, XrSystemId system_id, std::string *r_requirement_info) const override
std::vector< XrSwapchainImageBaseHeader * > createSwapchainImages(uint32_t image_count) override
void submitToSwapchainImage(XrSwapchainImageBaseHeader &swapchain_image, const GHOST_XrDrawViewInfo &draw_info) override
format
unsigned int uint32_t
Definition stdint.h:80