mirror of
https://github.com/blender/blender
synced 2026-10-25 03:07:01 +03:00
For now more than 20 years, Blender has been communicating with the host operating system through the GHOST module. At the time of its creation, Blender was still mostly written in C. As GHOST relied on C++ virtual inheritance to define abstract interfaces that are then implemented for each operating system, a C API had to be put in place to allow calling of such C++ functions from C, using opaque void pointer types to hold references to the abstract C++ interface types. Over the years, with Blender transitioning to C++, the C interface has become almost completely obsolete, hard to maintain, and is a common source of confusion and mistakes. With every GHOST method having to be implemented both in the abstract interface, common base class, OS specific implementation *and* in the C-API, to then be called from C++ through opaque handles, maintenance and expansion of this system has become needlessly difficult. In response to this problem, this PR refactors the GHOST module internals and the Blender calling code (in the WM, XR, GPU, and general OS dependent modules) to directly use and call the GHOST C++ class interfaces methods. Making for a simpler, cleaner and less error prone usage of the module. As well as providing better insight, IDE support and understanding of the module functionalities, and removing the need for opaque handle types and void pointers casting. Part of the 2025 Platform & Builds Code Quality Project (#151316) ## Main Changes ### Removal of opaque types and port of GHOST Types to C++ The GHOST opaque type handles (`GHOST_SystemHandle`, `GHOST_WindowHandle`, etc..) were removed in favor of directly accessing using and accessing their parent interface class. In addition to this, the main `GHOST_Types.h` header file was refactored to C++ (and renamed to `.hh`), dropping use of `typedef` for struct, enum and type alias and replacing them with direct C++ type definition and `using` declaration, as well as generally cleaning up the file from now outdated macros. ### Removal of the GHOST C-API interface, and port of calling code to C++ API The GHOST C-API interface (GHOST_C-api.h / GHOST_C-api.cc) and GHOST Path API (GHOST_Path-api.hh / GHOST_Path-api.cc) were removed in favor of directly using the GHOST interface class in the Blender calling code, making for a simpler and clearer API, allowing for clear and limited GHOST header includes, and generally simplifying the code. Some example of the new C++ API include (before/after): In general, throughout the code, number of casting is reduced. For example, in the WM code, a single `GHOST_IWindow *ghost_window` object can be created from `win->runtime->ghostwin` and be reused in a function, rather than casting the handle each time: In addition, certain C++ objects, such as GHOST_Rects, can be directly instantiated instead of being heap allocated: ### Replacement of void pointers in GPU backend code in favor GHOST interface pointer types With GHOST Types now being directly instantiable from within Blender code, the GPU backend code was improved in favor of replacing `void *` types referencing the GHOST graphic context with actual `GHOST_IContext *` interface pointer types, improving both type safety, general readability and removing the need for casting back and forth. See changes in `source/blender/gpu`. ### Conservation of the GHOST XR API As the XR part of the GHOST C-API didn't only provide opaque handle and C++ function calling, but also XR error handling via `GHOST_XR_CAPI_CALL{_RET}` macros, this part of the C-API was preserved in a new sub, XR specific API, exposed in the new `GHOST_Xr-api.hh` header and implemented in the existing `GHOST_Xr.cc` file. Following the rest of the refactor, the functions definition and prototypes were ported from using opaques `GHOST_XrContextHandle` to `GHOST_IXrContext *` pointer types. ### Removal of legacy GHOST OpenGL based tests In the GHOST module source tree, a `test` folder remained containing old tests dating back from the initial Git commit of ~2002. As these files have to be manually compiled and ran as a separate CMake target, are well outside our standard testing framework and code style, have outdated coverage, and mostly rely on pure OpenGL and now unsupported OpenGL code. The decision was made to remove them rather than uselessly port them to the C++ API. A possible future quality task could then be to re-implement proper, modern GHOST tests. *NOTE: See PR for additional API usage before/after examples.* Pull Request: https://projects.blender.org/blender/blender/pulls/151792
245 lines
9.1 KiB
C++
245 lines
9.1 KiB
C++
/* SPDX-FileCopyrightText: 2025 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup GHOST
|
|
*
|
|
* \brief Abstraction for XR (VR, AR, MR, ..) access via OpenXR.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "GHOST_IXrContext.hh"
|
|
#include "GHOST_Types.hh"
|
|
|
|
/* XR-context */
|
|
|
|
/**
|
|
* Set a custom callback to be executed whenever an error occurs. Should be set before calling
|
|
* #GHOST_XrContextCreate() to get error handling during context creation too.
|
|
*
|
|
* \param customdata: Handle to some data that will get passed to \a handler_fn should an error be
|
|
* thrown.
|
|
*/
|
|
void GHOST_XrErrorHandler(GHOST_XrErrorHandlerFn handler_fn, void *customdata);
|
|
|
|
/**
|
|
* \brief Initialize the Ghost XR-context.
|
|
*
|
|
* Includes setting up the OpenXR runtime link, querying available extensions and API layers,
|
|
* enabling extensions and API layers.
|
|
*
|
|
* \param create_info: Options for creating the XR-context, e.g. debug-flags and ordered array of
|
|
* graphics bindings to try enabling.
|
|
*/
|
|
GHOST_IXrContext *GHOST_XrContextCreate(const GHOST_XrContextCreateInfo *create_info);
|
|
/**
|
|
* Free a XR-context involving OpenXR runtime link destruction and freeing of all internal data.
|
|
*/
|
|
void GHOST_XrContextDestroy(GHOST_IXrContext *xr_context);
|
|
|
|
/**
|
|
* Set callbacks for binding and unbinding a graphics context for a session. The binding callback
|
|
* may create a new graphics context thereby. In fact that's the sole reason for this callback
|
|
* approach to binding. Just make sure to have an unbind function set that properly destructs.
|
|
*
|
|
* \param bind_fn: Function to retrieve (possibly create) a graphics context.
|
|
* \param unbind_fn: Function to release (possibly free) a graphics context.
|
|
*/
|
|
void GHOST_XrGraphicsContextBindFuncs(GHOST_IXrContext *xr_context,
|
|
GHOST_XrGraphicsContextBindFn bind_fn,
|
|
GHOST_XrGraphicsContextUnbindFn unbind_fn);
|
|
|
|
/**
|
|
* Set the drawing callback for views. A view would typically be either the left or the right eye,
|
|
* although other configurations are possible. When #GHOST_XrSessionDrawViews() is called to draw
|
|
* an XR frame, \a draw_view_fn is executed for each view.
|
|
*
|
|
* \param draw_view_fn: The callback to draw a single view for an XR frame.
|
|
*/
|
|
void GHOST_XrDrawViewFunc(GHOST_IXrContext *xr_context, GHOST_XrDrawViewFn draw_view_fn);
|
|
|
|
/**
|
|
* Set the callback to check if passthrough is enabled.
|
|
* If enabled, the passthrough composition layer is added in GHOST_XrSession::draw().
|
|
*
|
|
* \param passthrough_enabled_fn: The callback to check if passthrough is enabled.
|
|
*/
|
|
void GHOST_XrPassthroughEnabledFunc(GHOST_IXrContext *xr_context,
|
|
GHOST_XrPassthroughEnabledFn passthrough_enabled_fn);
|
|
|
|
/**
|
|
* Set the callback to force disable passthrough in case it is not supported.
|
|
* Called in GHOST_XrSession::draw().
|
|
*
|
|
* \param disable_passthrough_fn: The callback to disable passthrough.
|
|
*/
|
|
void GHOST_XrDisablePassthroughFunc(GHOST_IXrContext *xr_context,
|
|
GHOST_XrDisablePassthroughFn disable_passthrough_fn);
|
|
|
|
/* sessions */
|
|
/**
|
|
* Create internal session data for \a xr_context and ask the OpenXR runtime to invoke a session.
|
|
*
|
|
* \param begin_info: Options for the session creation.
|
|
*/
|
|
void GHOST_XrSessionStart(GHOST_IXrContext *xr_context,
|
|
const GHOST_XrSessionBeginInfo *begin_info);
|
|
/**
|
|
* Destruct internal session data for \a xr_context and ask the OpenXR runtime to stop a session.
|
|
*/
|
|
void GHOST_XrSessionEnd(GHOST_IXrContext *xr_context);
|
|
/**
|
|
* Draw a single frame by calling the view drawing callback defined by #GHOST_XrDrawViewFunc() for
|
|
* each view and submit it to the OpenXR runtime.
|
|
*
|
|
* \param customdata: Handle to some data that will get passed to the view drawing callback.
|
|
*/
|
|
void GHOST_XrSessionDrawViews(GHOST_IXrContext *xr_context, void *customdata);
|
|
/**
|
|
* Check if a \a xr_context has a session that, according to the OpenXR definition would be
|
|
* considered to be 'running'
|
|
* (https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#session_running).
|
|
*/
|
|
int GHOST_XrSessionIsRunning(const GHOST_IXrContext *xr_context);
|
|
|
|
/**
|
|
* Check if \a xr_context has a session that requires an upside-down frame-buffer (compared to
|
|
* GPU). If true, the render result should be flipped vertically for correct output.
|
|
* \note Only to be called after session start, may otherwise result in a false negative.
|
|
*/
|
|
int GHOST_XrSessionNeedsUpsideDownDrawing(const GHOST_IXrContext *xr_context);
|
|
|
|
/* events */
|
|
/**
|
|
* Invoke handling of all OpenXR events for \a xr_context. Should be called on every main-loop
|
|
* iteration and will early-exit if \a xr_context is nullptr (so caller doesn't have to check).
|
|
*
|
|
* \returns GHOST_kSuccess if any event was handled, otherwise GHOST_kFailure.
|
|
*/
|
|
GHOST_TSuccess GHOST_XrEventsHandle(GHOST_IXrContext *xr_context);
|
|
|
|
/* actions */
|
|
/**
|
|
* Create an OpenXR action set for input/output.
|
|
*/
|
|
int GHOST_XrCreateActionSet(GHOST_IXrContext *xr_context, const GHOST_XrActionSetInfo *info);
|
|
|
|
/**
|
|
* Destroy a previously created OpenXR action set.
|
|
*/
|
|
void GHOST_XrDestroyActionSet(GHOST_IXrContext *xr_context, const char *action_set_name);
|
|
|
|
/**
|
|
* Create OpenXR input/output actions.
|
|
*/
|
|
int GHOST_XrCreateActions(GHOST_IXrContext *xr_context,
|
|
const char *action_set_name,
|
|
uint32_t count,
|
|
const GHOST_XrActionInfo *infos);
|
|
|
|
/**
|
|
* Destroy previously created OpenXR actions.
|
|
*/
|
|
void GHOST_XrDestroyActions(GHOST_IXrContext *xr_context,
|
|
const char *action_set_name,
|
|
uint32_t count,
|
|
const char *const *action_names);
|
|
|
|
/**
|
|
* Create input/output path bindings for OpenXR actions.
|
|
*/
|
|
int GHOST_XrCreateActionBindings(GHOST_IXrContext *xr_context,
|
|
const char *action_set_name,
|
|
uint32_t count,
|
|
const GHOST_XrActionProfileInfo *infos);
|
|
|
|
/**
|
|
* Destroy previously created bindings for OpenXR actions.
|
|
*/
|
|
void GHOST_XrDestroyActionBindings(GHOST_IXrContext *xr_context,
|
|
const char *action_set_name,
|
|
uint32_t count,
|
|
const char *const *action_names,
|
|
const char *const *profile_paths);
|
|
|
|
/**
|
|
* Attach all created action sets to the current OpenXR session.
|
|
*/
|
|
int GHOST_XrAttachActionSets(GHOST_IXrContext *xr_context);
|
|
|
|
/**
|
|
* Update button/tracking states for OpenXR actions.
|
|
*
|
|
* \param action_set_name: The name of the action set to sync. If nullptr, all action sets
|
|
* attached to the session will be synced.
|
|
*/
|
|
int GHOST_XrSyncActions(GHOST_IXrContext *xr_context, const char *action_set_name);
|
|
|
|
/**
|
|
* Apply an OpenXR haptic output action.
|
|
*/
|
|
int GHOST_XrApplyHapticAction(GHOST_IXrContext *xr_context_handle,
|
|
const char *action_set_name,
|
|
const char *action_name,
|
|
const char *subaction_path,
|
|
const int64_t *duration,
|
|
const float *frequency,
|
|
const float *amplitude);
|
|
|
|
/**
|
|
* Stop a previously applied OpenXR haptic output action.
|
|
*/
|
|
void GHOST_XrStopHapticAction(GHOST_IXrContext *xr_context_handle,
|
|
const char *action_set_name,
|
|
const char *action_name,
|
|
const char *subaction_path);
|
|
|
|
/**
|
|
* Get action set custom data (owned by Blender, not GHOST).
|
|
*/
|
|
void *GHOST_XrGetActionSetCustomdata(GHOST_IXrContext *xr_context, const char *action_set_name);
|
|
|
|
/**
|
|
* Get action custom data (owned by Blender, not GHOST).
|
|
*/
|
|
void *GHOST_XrGetActionCustomdata(GHOST_IXrContext *xr_context,
|
|
const char *action_set_name,
|
|
const char *action_name);
|
|
|
|
/**
|
|
* Get the number of actions in an action set.
|
|
*/
|
|
unsigned int GHOST_XrGetActionCount(GHOST_IXrContext *xr_context, const char *action_set_name);
|
|
|
|
/**
|
|
* Get custom data for all actions in an action set.
|
|
*/
|
|
void GHOST_XrGetActionCustomdataArray(GHOST_IXrContext *xr_context,
|
|
const char *action_set_name,
|
|
void **r_customdata_array);
|
|
|
|
/* controller model */
|
|
/**
|
|
* Load the OpenXR controller model.
|
|
*/
|
|
int GHOST_XrLoadControllerModel(GHOST_IXrContext *xr_context, const char *subaction_path);
|
|
|
|
/**
|
|
* Unload the OpenXR controller model.
|
|
*/
|
|
void GHOST_XrUnloadControllerModel(GHOST_IXrContext *xr_context, const char *subaction_path);
|
|
|
|
/**
|
|
* Update component transforms for the OpenXR controller model.
|
|
*/
|
|
int GHOST_XrUpdateControllerModelComponents(GHOST_IXrContext *xr_context,
|
|
const char *subaction_path);
|
|
|
|
/**
|
|
* Get vertex data for the OpenXR controller model.
|
|
*/
|
|
int GHOST_XrGetControllerModelData(GHOST_IXrContext *xr_context,
|
|
const char *subaction_path,
|
|
GHOST_XrControllerModelData *r_data);
|