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
8
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
499 bool needsUpsideDownDrawing(GHOST_Context &) const
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)
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object instance
EGLConfig getConfig() const
EGLDisplay getDisplay() const
EGLContext getContext() const
virtual bool isUpsideDown() const
GHOST_IXrGraphicsBinding()=default
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
union GHOST_IXrGraphicsBinding::@032107113146203207234320050047375011224045132242 oxr_binding
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
input_tx image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "preview_img") .compute_source("compositor_compute_preview.glsl") .do_static_compilation(true)
format
unsigned int uint32_t
Definition stdint.h:80