Implementing OpenXR driver
This commit is contained in:
parent
65bae5a341
commit
a78a9fee71
53 changed files with 6359 additions and 168 deletions
|
@ -173,6 +173,7 @@ opts.Add(BoolVariable("minizip", "Enable ZIP archive support using minizip", Tru
|
|||
opts.Add(BoolVariable("xaudio2", "Enable the XAudio2 audio driver", False))
|
||||
opts.Add(BoolVariable("vulkan", "Enable the vulkan video driver", True))
|
||||
opts.Add(BoolVariable("opengl3", "Enable the OpenGL/GLES3 video driver", True))
|
||||
opts.Add(BoolVariable("openxr", "Enable the OpenXR driver", True))
|
||||
opts.Add("custom_modules", "A list of comma-separated directory paths containing custom modules to build.", "")
|
||||
opts.Add(BoolVariable("custom_modules_recursive", "Detect custom modules recursively for each specified path.", True))
|
||||
opts.Add(BoolVariable("use_volk", "Use the volk library to load the Vulkan loader dynamically", True))
|
||||
|
|
|
@ -1915,8 +1915,23 @@
|
|||
</member>
|
||||
<member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
|
||||
</member>
|
||||
<member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false">
|
||||
If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled.
|
||||
<member name="xr/openxr/default_action_map" type="String" setter="" getter="" default=""res://default_action_map.tres"">
|
||||
Action map configuration to load by default.
|
||||
</member>
|
||||
<member name="xr/openxr/enabled" type="bool" setter="" getter="" default="false">
|
||||
If [code]true[/code] Godot will setup and initialise OpenXR on startup.
|
||||
</member>
|
||||
<member name="xr/openxr/form_factor" type="int" setter="" getter="" default=""0"">
|
||||
Specify whether OpenXR should be configured for an HMD or a hand held device.
|
||||
</member>
|
||||
<member name="xr/openxr/reference_space" type="int" setter="" getter="" default=""1"">
|
||||
Specify the default reference space.
|
||||
</member>
|
||||
<member name="xr/openxr/view_configuration" type="int" setter="" getter="" default=""1"">
|
||||
Specify the view configuration with which to configure OpenXR settting up either Mono or Stereo rendering.
|
||||
</member>
|
||||
<member name="xr/shaders/enabled" type="bool" setter="" getter="" default="false">
|
||||
If [code]true[/code], Godot will compile shaders required for XR.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
||||
|
|
|
@ -41,12 +41,6 @@
|
|||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0">
|
||||
The degree to which the controller vibrates. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code]. If changed, updates [member XRPositionalTracker.rumble] accordingly.
|
||||
This is a useful property to animate if you want the controller to vibrate for a limited duration.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="button_pressed">
|
||||
<argument index="0" name="name" type="String" />
|
||||
|
|
|
@ -72,9 +72,6 @@
|
|||
- [code]left_hand[/code] identifies the controller held in the players left hand
|
||||
- [code]right_hand[/code] identifies the controller held in the players right hand
|
||||
</member>
|
||||
<member name="rumble" type="float" setter="set_rumble" getter="get_rumble" default="0.0">
|
||||
The degree to which the tracker rumbles. Ranges from [code]0.0[/code] to [code]1.0[/code] with precision [code].01[/code].
|
||||
</member>
|
||||
<member name="type" type="int" setter="set_tracker_type" getter="get_tracker_type" enum="XRServer.TrackerType" default="128">
|
||||
The type of tracker.
|
||||
</member>
|
||||
|
|
|
@ -2118,6 +2118,124 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
|
|||
return id;
|
||||
}
|
||||
|
||||
RID RenderingDeviceVulkan::texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
// This method creates a texture object using a VkImage created by an extension, module or other external source (OpenXR uses this).
|
||||
VkImage image = (VkImage)p_image;
|
||||
|
||||
Texture texture;
|
||||
texture.image = image;
|
||||
// if we leave texture.allocation as a nullptr, would that be enough to detect we don't "own" the image?
|
||||
// also leave texture.allocation_info alone
|
||||
// we'll set texture.view later on
|
||||
texture.type = p_type;
|
||||
texture.format = p_format;
|
||||
texture.samples = p_samples;
|
||||
texture.width = p_width;
|
||||
texture.height = p_height;
|
||||
texture.depth = p_depth;
|
||||
texture.layers = p_layers;
|
||||
texture.mipmaps = 0; // maybe make this settable too?
|
||||
texture.usage_flags = p_flags;
|
||||
texture.base_mipmap = 0;
|
||||
texture.base_layer = 0;
|
||||
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
|
||||
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);
|
||||
|
||||
// Do we need to do something with texture.layout ?
|
||||
|
||||
if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
texture.read_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
texture.barrier_aspect_mask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
|
||||
// if (format_has_stencil(p_format.format)) {
|
||||
// texture.barrier_aspect_mask |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||
// }
|
||||
} else {
|
||||
texture.read_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
texture.barrier_aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
|
||||
// Create a view for us to use
|
||||
|
||||
VkImageViewCreateInfo image_view_create_info;
|
||||
image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
image_view_create_info.pNext = nullptr;
|
||||
image_view_create_info.flags = 0;
|
||||
image_view_create_info.image = texture.image;
|
||||
|
||||
static const VkImageViewType view_types[TEXTURE_TYPE_MAX] = {
|
||||
VK_IMAGE_VIEW_TYPE_1D,
|
||||
VK_IMAGE_VIEW_TYPE_2D,
|
||||
VK_IMAGE_VIEW_TYPE_3D,
|
||||
VK_IMAGE_VIEW_TYPE_CUBE,
|
||||
VK_IMAGE_VIEW_TYPE_1D_ARRAY,
|
||||
VK_IMAGE_VIEW_TYPE_2D_ARRAY,
|
||||
VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
|
||||
};
|
||||
|
||||
image_view_create_info.viewType = view_types[texture.type];
|
||||
image_view_create_info.format = vulkan_formats[texture.format];
|
||||
|
||||
static const VkComponentSwizzle component_swizzles[TEXTURE_SWIZZLE_MAX] = {
|
||||
VK_COMPONENT_SWIZZLE_IDENTITY,
|
||||
VK_COMPONENT_SWIZZLE_ZERO,
|
||||
VK_COMPONENT_SWIZZLE_ONE,
|
||||
VK_COMPONENT_SWIZZLE_R,
|
||||
VK_COMPONENT_SWIZZLE_G,
|
||||
VK_COMPONENT_SWIZZLE_B,
|
||||
VK_COMPONENT_SWIZZLE_A
|
||||
};
|
||||
|
||||
// hardcode for now, maybe make this settable from outside..
|
||||
image_view_create_info.components.r = component_swizzles[TEXTURE_SWIZZLE_R];
|
||||
image_view_create_info.components.g = component_swizzles[TEXTURE_SWIZZLE_G];
|
||||
image_view_create_info.components.b = component_swizzles[TEXTURE_SWIZZLE_B];
|
||||
image_view_create_info.components.a = component_swizzles[TEXTURE_SWIZZLE_A];
|
||||
|
||||
image_view_create_info.subresourceRange.baseMipLevel = 0;
|
||||
image_view_create_info.subresourceRange.levelCount = texture.mipmaps;
|
||||
image_view_create_info.subresourceRange.baseArrayLayer = 0;
|
||||
image_view_create_info.subresourceRange.layerCount = texture.layers;
|
||||
if (texture.usage_flags & TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
|
||||
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
} else {
|
||||
image_view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
}
|
||||
|
||||
VkResult err = vkCreateImageView(device, &image_view_create_info, nullptr, &texture.view);
|
||||
|
||||
if (err) {
|
||||
// vmaDestroyImage(allocator, texture.image, texture.allocation);
|
||||
ERR_FAIL_V_MSG(RID(), "vkCreateImageView failed with error " + itos(err) + ".");
|
||||
}
|
||||
|
||||
//barrier to set layout
|
||||
{
|
||||
VkImageMemoryBarrier image_memory_barrier;
|
||||
image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
image_memory_barrier.pNext = nullptr;
|
||||
image_memory_barrier.srcAccessMask = 0;
|
||||
image_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
image_memory_barrier.newLayout = texture.layout;
|
||||
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
image_memory_barrier.image = texture.image;
|
||||
image_memory_barrier.subresourceRange.aspectMask = texture.barrier_aspect_mask;
|
||||
image_memory_barrier.subresourceRange.baseMipLevel = 0;
|
||||
image_memory_barrier.subresourceRange.levelCount = texture.mipmaps;
|
||||
image_memory_barrier.subresourceRange.baseArrayLayer = 0;
|
||||
image_memory_barrier.subresourceRange.layerCount = texture.layers;
|
||||
|
||||
vkCmdPipelineBarrier(frames[frame].setup_command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
|
||||
}
|
||||
|
||||
RID id = texture_owner.make_rid(texture);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps, TextureSliceType p_slice_type) {
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
|
|
|
@ -1037,6 +1037,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
|
|||
public:
|
||||
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>());
|
||||
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture);
|
||||
virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers);
|
||||
|
||||
virtual RID texture_create_shared_from_slice(const TextureView &p_view, RID p_with_texture, uint32_t p_layer, uint32_t p_mipmap, uint32_t p_mipmaps = 1, TextureSliceType p_slice_type = TEXTURE_SLICE_2D);
|
||||
virtual Error texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL);
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define APP_SHORT_NAME "GodotEngine"
|
||||
|
||||
VulkanHooks *VulkanContext::vulkan_hooks = nullptr;
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL VulkanContext::_debug_messenger_callback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
|
@ -695,19 +697,27 @@ Error VulkanContext::_create_instance() {
|
|||
inst_info.pNext = &dbg_report_callback_create_info;
|
||||
}
|
||||
|
||||
VkResult err = vkCreateInstance(&inst_info, nullptr, &inst);
|
||||
ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
|
||||
"Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
|
||||
"vkCreateInstance Failure");
|
||||
ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
|
||||
"Cannot find a specified extension library.\n"
|
||||
"Make sure your layers path is set appropriately.\n"
|
||||
"vkCreateInstance Failure");
|
||||
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
|
||||
"vkCreateInstance failed.\n\n"
|
||||
"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
|
||||
"Please look at the Getting Started guide for additional information.\n"
|
||||
"vkCreateInstance Failure");
|
||||
VkResult err;
|
||||
|
||||
if (vulkan_hooks) {
|
||||
if (!vulkan_hooks->create_vulkan_instance(&inst_info, &inst)) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
} else {
|
||||
err = vkCreateInstance(&inst_info, nullptr, &inst);
|
||||
ERR_FAIL_COND_V_MSG(err == VK_ERROR_INCOMPATIBLE_DRIVER, ERR_CANT_CREATE,
|
||||
"Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
|
||||
"vkCreateInstance Failure");
|
||||
ERR_FAIL_COND_V_MSG(err == VK_ERROR_EXTENSION_NOT_PRESENT, ERR_CANT_CREATE,
|
||||
"Cannot find a specified extension library.\n"
|
||||
"Make sure your layers path is set appropriately.\n"
|
||||
"vkCreateInstance Failure");
|
||||
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE,
|
||||
"vkCreateInstance failed.\n\n"
|
||||
"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
|
||||
"Please look at the Getting Started guide for additional information.\n"
|
||||
"vkCreateInstance Failure");
|
||||
}
|
||||
|
||||
inst_initialized = true;
|
||||
|
||||
|
@ -820,107 +830,122 @@ Error VulkanContext::_create_physical_device(VkSurfaceKHR p_surface) {
|
|||
{ 0, nullptr },
|
||||
};
|
||||
|
||||
// TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
|
||||
// The device should really be a preference, but for now choosing a discrete GPU over the
|
||||
// integrated one is better than the default.
|
||||
|
||||
int32_t device_index = -1;
|
||||
int type_selected = -1;
|
||||
print_verbose("Vulkan devices:");
|
||||
for (uint32_t i = 0; i < gpu_count; ++i) {
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(physical_devices[i], &props);
|
||||
|
||||
bool present_supported = false;
|
||||
|
||||
uint32_t device_queue_family_count = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
|
||||
VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
|
||||
for (uint32_t j = 0; j < device_queue_family_count; j++) {
|
||||
VkBool32 supports;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports);
|
||||
if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) {
|
||||
present_supported = true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (vulkan_hooks) {
|
||||
if (!vulkan_hooks->get_physical_device(&gpu)) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
String name = props.deviceName;
|
||||
String vendor = "Unknown";
|
||||
String dev_type;
|
||||
switch (props.deviceType) {
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
|
||||
dev_type = "Discrete";
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
|
||||
dev_type = "Integrated";
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
|
||||
dev_type = "Virtual";
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
|
||||
dev_type = "CPU";
|
||||
} break;
|
||||
default: {
|
||||
dev_type = "Other";
|
||||
} break;
|
||||
}
|
||||
uint32_t vendor_idx = 0;
|
||||
while (vendor_names[vendor_idx].name != nullptr) {
|
||||
if (props.vendorID == vendor_names[vendor_idx].id) {
|
||||
vendor = vendor_names[vendor_idx].name;
|
||||
|
||||
// not really needed but nice to print the correct entry
|
||||
for (uint32_t i = 0; i < gpu_count; ++i) {
|
||||
if (physical_devices[i] == gpu) {
|
||||
device_index = i;
|
||||
break;
|
||||
}
|
||||
vendor_idx++;
|
||||
}
|
||||
free(device_queue_props);
|
||||
print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
|
||||
} else {
|
||||
// TODO: At least on Linux Laptops integrated GPUs fail with Vulkan in many instances.
|
||||
// The device should really be a preference, but for now choosing a discrete GPU over the
|
||||
// integrated one is better than the default.
|
||||
|
||||
if (present_supported) { // Select first supported device of preferred type: Discrete > Integrated > Virtual > CPU > Other.
|
||||
int type_selected = -1;
|
||||
print_verbose("Vulkan devices:");
|
||||
for (uint32_t i = 0; i < gpu_count; ++i) {
|
||||
VkPhysicalDeviceProperties props;
|
||||
vkGetPhysicalDeviceProperties(physical_devices[i], &props);
|
||||
|
||||
bool present_supported = false;
|
||||
|
||||
uint32_t device_queue_family_count = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, nullptr);
|
||||
VkQueueFamilyProperties *device_queue_props = (VkQueueFamilyProperties *)malloc(device_queue_family_count * sizeof(VkQueueFamilyProperties));
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices[i], &device_queue_family_count, device_queue_props);
|
||||
for (uint32_t j = 0; j < device_queue_family_count; j++) {
|
||||
VkBool32 supports;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(physical_devices[i], j, p_surface, &supports);
|
||||
if (supports && ((device_queue_props[j].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)) {
|
||||
present_supported = true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
String name = props.deviceName;
|
||||
String vendor = "Unknown";
|
||||
String dev_type;
|
||||
switch (props.deviceType) {
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
|
||||
if (type_selected < 4) {
|
||||
type_selected = 4;
|
||||
device_index = i;
|
||||
}
|
||||
dev_type = "Discrete";
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
|
||||
if (type_selected < 3) {
|
||||
type_selected = 3;
|
||||
device_index = i;
|
||||
}
|
||||
dev_type = "Integrated";
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
|
||||
if (type_selected < 2) {
|
||||
type_selected = 2;
|
||||
device_index = i;
|
||||
}
|
||||
dev_type = "Virtual";
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
|
||||
if (type_selected < 1) {
|
||||
type_selected = 1;
|
||||
device_index = i;
|
||||
}
|
||||
dev_type = "CPU";
|
||||
} break;
|
||||
default: {
|
||||
if (type_selected < 0) {
|
||||
type_selected = 0;
|
||||
device_index = i;
|
||||
}
|
||||
dev_type = "Other";
|
||||
} break;
|
||||
}
|
||||
uint32_t vendor_idx = 0;
|
||||
while (vendor_names[vendor_idx].name != nullptr) {
|
||||
if (props.vendorID == vendor_names[vendor_idx].id) {
|
||||
vendor = vendor_names[vendor_idx].name;
|
||||
break;
|
||||
}
|
||||
vendor_idx++;
|
||||
}
|
||||
free(device_queue_props);
|
||||
print_verbose(" #" + itos(i) + ": " + vendor + " " + name + " - " + (present_supported ? "Supported" : "Unsupported") + ", " + dev_type);
|
||||
|
||||
if (present_supported) { // Select first supported device of preffered type: Discrete > Integrated > Virtual > CPU > Other.
|
||||
switch (props.deviceType) {
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: {
|
||||
if (type_selected < 4) {
|
||||
type_selected = 4;
|
||||
device_index = i;
|
||||
}
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: {
|
||||
if (type_selected < 3) {
|
||||
type_selected = 3;
|
||||
device_index = i;
|
||||
}
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: {
|
||||
if (type_selected < 2) {
|
||||
type_selected = 2;
|
||||
device_index = i;
|
||||
}
|
||||
} break;
|
||||
case VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_CPU: {
|
||||
if (type_selected < 1) {
|
||||
type_selected = 1;
|
||||
device_index = i;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
if (type_selected < 0) {
|
||||
type_selected = 0;
|
||||
device_index = i;
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
|
||||
if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) {
|
||||
device_index = user_device_index;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues.");
|
||||
|
||||
gpu = physical_devices[device_index];
|
||||
}
|
||||
|
||||
int32_t user_device_index = Engine::get_singleton()->get_gpu_index(); // Force user selected GPU.
|
||||
if (user_device_index >= 0 && user_device_index < (int32_t)gpu_count) {
|
||||
device_index = user_device_index;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(device_index == -1, ERR_CANT_CREATE, "None of Vulkan devices supports both graphics and present queues.");
|
||||
|
||||
gpu = physical_devices[device_index];
|
||||
free(physical_devices);
|
||||
|
||||
/* Look for device extensions */
|
||||
|
@ -1148,8 +1173,14 @@ Error VulkanContext::_create_device() {
|
|||
sdevice.queueCreateInfoCount = 2;
|
||||
}
|
||||
|
||||
err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
|
||||
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
|
||||
if (vulkan_hooks) {
|
||||
if (!vulkan_hooks->create_vulkan_device(&sdevice, &device)) {
|
||||
return ERR_CANT_CREATE;
|
||||
}
|
||||
} else {
|
||||
err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
|
||||
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@
|
|||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
#include "vulkan_hooks.h"
|
||||
|
||||
class VulkanContext {
|
||||
public:
|
||||
struct SubgroupCapabilities {
|
||||
|
@ -86,6 +88,7 @@ private:
|
|||
FRAME_LAG = 2
|
||||
};
|
||||
|
||||
static VulkanHooks *vulkan_hooks;
|
||||
VkInstance inst = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice gpu = VK_NULL_HANDLE;
|
||||
VkPhysicalDeviceProperties gpu_props;
|
||||
|
@ -267,6 +270,8 @@ public:
|
|||
VkQueue get_graphics_queue() const;
|
||||
uint32_t get_graphics_queue_family_index() const;
|
||||
|
||||
static void set_vulkan_hooks(VulkanHooks *p_vulkan_hooks) { vulkan_hooks = p_vulkan_hooks; };
|
||||
|
||||
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
|
||||
int window_get_width(DisplayServer::WindowID p_window = 0);
|
||||
int window_get_height(DisplayServer::WindowID p_window = 0);
|
||||
|
|
48
drivers/vulkan/vulkan_hooks.h
Normal file
48
drivers/vulkan/vulkan_hooks.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*************************************************************************/
|
||||
/* vulkan_hooks.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef VULKAN_HOOKS_H
|
||||
#define VULKAN_HOOKS_H
|
||||
|
||||
#ifdef USE_VOLK
|
||||
#include <volk.h>
|
||||
#else
|
||||
#include <vulkan/vulkan.h>
|
||||
#endif
|
||||
|
||||
class VulkanHooks {
|
||||
public:
|
||||
virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) { return false; };
|
||||
virtual bool get_physical_device(VkPhysicalDevice *r_device) { return false; };
|
||||
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) { return false; };
|
||||
virtual ~VulkanHooks(){};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1963,6 +1963,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
|
|||
return OK;
|
||||
}
|
||||
|
||||
String Main::get_rendering_driver_name() {
|
||||
return rendering_driver;
|
||||
}
|
||||
|
||||
// everything the main loop needs to know about frame timings
|
||||
static MainTimerSync main_timer_sync;
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
static int test_entrypoint(int argc, char *argv[], bool &tests_need_run);
|
||||
static Error setup(const char *execpath, int argc, char *argv[], bool p_second_phase = true);
|
||||
static Error setup2(Thread::ID p_main_tid_override = 0);
|
||||
static String get_rendering_driver_name();
|
||||
#ifdef TESTS_ENABLED
|
||||
static Error test_setup();
|
||||
static void test_cleanup();
|
||||
|
|
87
modules/openxr/SCsub
Normal file
87
modules/openxr/SCsub
Normal file
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_openxr = env_modules.Clone()
|
||||
|
||||
#################################################
|
||||
# Add in our Khronos OpenXR loader
|
||||
|
||||
thirdparty_obj = []
|
||||
thirdparty_dir = "#thirdparty/openxr"
|
||||
|
||||
env_openxr.Prepend(
|
||||
CPPPATH=[
|
||||
thirdparty_dir,
|
||||
thirdparty_dir + "/include",
|
||||
thirdparty_dir + "/src",
|
||||
thirdparty_dir + "/src/common",
|
||||
thirdparty_dir + "/src/external/jsoncpp/include",
|
||||
thirdparty_dir + "/src/loader",
|
||||
]
|
||||
)
|
||||
|
||||
# may need to check and set:
|
||||
# - XR_USE_TIMESPEC
|
||||
|
||||
env_thirdparty = env_openxr.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"])
|
||||
|
||||
if env["platform"] == "android":
|
||||
# may need to set OPENXR_ANDROID_VERSION_SUFFIX
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"])
|
||||
|
||||
# may need to include java parts of the openxr loader
|
||||
elif env["platform"] == "linuxbsd":
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_LINUX", "XR_USE_PLATFORM_XLIB"])
|
||||
# FIXME: Review what needs to be set for Android and macOS.
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["HAVE_SECURE_GETENV"])
|
||||
elif env["platform"] == "windows":
|
||||
env_thirdparty.AppendUnique(CPPDEFINES=["XR_OS_WINDOWS", "NOMINMAX", "XR_USE_PLATFORM_WIN32"])
|
||||
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c")
|
||||
|
||||
# add in common files (hope these don't clash with us)
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/common/object_info.cpp")
|
||||
|
||||
# add in external jsoncpp dependency
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_value.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp")
|
||||
|
||||
# add in load
|
||||
if env["platform"] == "android":
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/android_utilities.cpp")
|
||||
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_core.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_instance.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/loader_logger.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/manifest_file.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp")
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp")
|
||||
|
||||
env.modules_sources += thirdparty_obj
|
||||
|
||||
#################################################
|
||||
# And include our module source
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_openxr.add_source_files(module_obj, "*.cpp")
|
||||
env_openxr.add_source_files(module_obj, "action_map/*.cpp")
|
||||
|
||||
# We're a little more targetted with our extensions
|
||||
if env["platform"] == "android":
|
||||
env_openxr.add_source_files(module_obj, "extensions/openxr_android_extension.cpp")
|
||||
if env["vulkan"]:
|
||||
env_openxr.add_source_files(module_obj, "extensions/openxr_vulkan_extension.cpp")
|
||||
|
||||
env.modules_sources += module_obj
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
env.Depends(module_obj, thirdparty_obj)
|
91
modules/openxr/action_map/openxr_action.cpp
Normal file
91
modules/openxr/action_map/openxr_action.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_action.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_action.h"
|
||||
|
||||
void OpenXRAction::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name);
|
||||
ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRAction::get_localized_name);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_action_type", "action_type"), &OpenXRAction::set_action_type);
|
||||
ClassDB::bind_method(D_METHOD("get_action_type"), &OpenXRAction::get_action_type);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "action_type", PROPERTY_HINT_ENUM, "bool,float,vector2,pose"), "set_action_type", "get_action_type");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_toplevel_paths", "toplevel_paths"), &OpenXRAction::set_toplevel_paths);
|
||||
ClassDB::bind_method(D_METHOD("get_toplevel_paths"), &OpenXRAction::get_toplevel_paths);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "toplevel_paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_toplevel_paths", "get_toplevel_paths");
|
||||
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_BOOL);
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_FLOAT);
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_VECTOR2);
|
||||
BIND_ENUM_CONSTANT(OPENXR_ACTION_POSE);
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRAction> action;
|
||||
action.instantiate();
|
||||
action->set_name(String(p_name));
|
||||
action->set_localized_name(String(p_localized_name));
|
||||
action->set_action_type(p_action_type);
|
||||
action->parse_toplevel_paths(String(p_toplevel_paths));
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
void OpenXRAction::set_localized_name(const String p_localized_name) {
|
||||
localized_name = p_localized_name;
|
||||
}
|
||||
|
||||
String OpenXRAction::get_localized_name() const {
|
||||
return localized_name;
|
||||
}
|
||||
|
||||
void OpenXRAction::set_action_type(const OpenXRAction::ActionType p_action_type) {
|
||||
action_type = p_action_type;
|
||||
}
|
||||
|
||||
OpenXRAction::ActionType OpenXRAction::get_action_type() const {
|
||||
return action_type;
|
||||
}
|
||||
|
||||
void OpenXRAction::set_toplevel_paths(const PackedStringArray p_toplevel_paths) {
|
||||
toplevel_paths = p_toplevel_paths;
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRAction::get_toplevel_paths() const {
|
||||
return toplevel_paths;
|
||||
}
|
||||
|
||||
void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) {
|
||||
toplevel_paths = p_toplevel_paths.split(",", false);
|
||||
}
|
74
modules/openxr/action_map/openxr_action.h
Normal file
74
modules/openxr/action_map/openxr_action.h
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_action.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_ACTION_H
|
||||
#define OPENXR_ACTION_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
class OpenXRAction : public Resource {
|
||||
GDCLASS(OpenXRAction, Resource);
|
||||
|
||||
public:
|
||||
enum ActionType {
|
||||
OPENXR_ACTION_BOOL,
|
||||
OPENXR_ACTION_FLOAT,
|
||||
OPENXR_ACTION_VECTOR2,
|
||||
OPENXR_ACTION_POSE,
|
||||
OPENXR_ACTION_HAPTIC,
|
||||
};
|
||||
|
||||
private:
|
||||
String localized_name;
|
||||
ActionType action_type = OPENXR_ACTION_FLOAT;
|
||||
|
||||
PackedStringArray toplevel_paths;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths);
|
||||
|
||||
void set_localized_name(const String p_localized_name);
|
||||
String get_localized_name() const;
|
||||
|
||||
void set_action_type(const ActionType p_action_type);
|
||||
ActionType get_action_type() const;
|
||||
|
||||
void set_toplevel_paths(const PackedStringArray p_toplevel_paths);
|
||||
PackedStringArray get_toplevel_paths() const;
|
||||
|
||||
void parse_toplevel_paths(const String p_toplevel_paths);
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST(OpenXRAction::ActionType);
|
||||
|
||||
#endif // !OPENXR_ACTION_H
|
261
modules/openxr/action_map/openxr_action_map.cpp
Normal file
261
modules/openxr/action_map/openxr_action_map.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_action_map.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_action_map.h"
|
||||
|
||||
void OpenXRActionMap::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_action_sets", "action_sets"), &OpenXRActionMap::set_action_sets);
|
||||
ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set);
|
||||
ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_interaction_profiles", "interaction_profiles"), &OpenXRActionMap::set_interaction_profiles);
|
||||
ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile);
|
||||
ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("create_default_action_sets"), &OpenXRActionMap::create_default_action_sets);
|
||||
}
|
||||
|
||||
void OpenXRActionMap::set_action_sets(Array p_action_sets) {
|
||||
action_sets = p_action_sets;
|
||||
}
|
||||
|
||||
Array OpenXRActionMap::get_action_sets() const {
|
||||
return action_sets;
|
||||
}
|
||||
|
||||
void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {
|
||||
ERR_FAIL_COND(p_action_set.is_null());
|
||||
|
||||
if (action_sets.find(p_action_set) == -1) {
|
||||
action_sets.push_back(p_action_set);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
|
||||
int idx = action_sets.find(p_action_set);
|
||||
if (idx != -1) {
|
||||
action_sets.remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
|
||||
interaction_profiles = p_interaction_profiles;
|
||||
}
|
||||
|
||||
Array OpenXRActionMap::get_interaction_profiles() const {
|
||||
return interaction_profiles;
|
||||
}
|
||||
|
||||
void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
|
||||
ERR_FAIL_COND(p_interaction_profile.is_null());
|
||||
|
||||
if (interaction_profiles.find(p_interaction_profile) == -1) {
|
||||
interaction_profiles.push_back(p_interaction_profile);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
|
||||
int idx = interaction_profiles.find(p_interaction_profile);
|
||||
if (idx != -1) {
|
||||
interaction_profiles.remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionMap::create_default_action_sets() {
|
||||
// Note, if you make changes here make sure to delete your default_action_map.tres file of it will load an old version.
|
||||
|
||||
// Create our Godot action set
|
||||
Ref<OpenXRActionSet> action_set = OpenXRActionSet::new_action_set("godot", "Godot action set");
|
||||
add_action_set(action_set);
|
||||
|
||||
// Create our actions
|
||||
Ref<OpenXRAction> trigger = action_set->add_new_action("trigger", "Trigger", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> trigger_click = action_set->add_new_action("trigger_click", "Trigger click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> trigger_touch = action_set->add_new_action("trigger_touch", "Trigger touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip = action_set->add_new_action("grip", "Grip", OpenXRAction::OPENXR_ACTION_FLOAT, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip_click = action_set->add_new_action("grip_click", "Grip click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip_touch = action_set->add_new_action("grip_touch", "Grip touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> primary = action_set->add_new_action("primary", "Primary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> primary_click = action_set->add_new_action("primary_click", "Primary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> primary_touch = action_set->add_new_action("primary_touch", "Primary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> secondary = action_set->add_new_action("secondary", "Secondary joystick/thumbstick/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> secondary_click = action_set->add_new_action("secondary_click", "Secondary joystick/thumbstick/trackpad click", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> secondary_touch = action_set->add_new_action("secondary_touch", "Secondary joystick/thumbstick/trackpad touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> menu_button = action_set->add_new_action("menu_button", "Menu button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> select_button = action_set->add_new_action("select_button", "Select button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> ax_button = action_set->add_new_action("ax_button", "A/X button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> ax_touch = action_set->add_new_action("ax_touch", "A/X touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> by_button = action_set->add_new_action("by_button", "B/Y button", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> by_touch = action_set->add_new_action("by_touch", "B/Y touching", OpenXRAction::OPENXR_ACTION_BOOL, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> default_pose = action_set->add_new_action("default_pose", "Default pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> aim_pose = action_set->add_new_action("aim_pose", "Aim pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> grip_pose = action_set->add_new_action("grip_pose", "Grip pose", OpenXRAction::OPENXR_ACTION_POSE, "/user/hand/left,/user/hand/right");
|
||||
Ref<OpenXRAction> haptic = action_set->add_new_action("haptic", "Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC, "/user/hand/left,/user/hand/right");
|
||||
|
||||
// Create our interaction profiles
|
||||
Ref<OpenXRInteractionProfile> profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/khr/simple_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
profile->add_new_binding(select_button, "/user/hand/left/input/select/click,/user/hand/right/input/select/click");
|
||||
// generic has no support for triggers, grip, A/B buttons, nor joystick/trackpad inputs
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Vive controller profile
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
profile->add_new_binding(select_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click");
|
||||
// wmr controller has no a/b/x/y buttons
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our vive controller is our trackpad
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
// vive controllers have no secondary input
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our WMR controller profile
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/microsoft/motion_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
// wmr controllers have no select button we can use
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
// wmr controller has no a/b/x/y buttons
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // OpenXR will conver float to bool
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click"); // OpenXR will convert bool to float
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
|
||||
// primary on our wmr controller is our thumbstick, no touch
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
// secondary on our wmr controller is our trackpad
|
||||
profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
|
||||
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our HP MR controller profile
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
// hpmr controllers have no select button we can use
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
|
||||
// hpmr controllers only register click, not touch, on our a/b/x/y buttons
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
// primary on our hpmr controller is our thumbstick
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
// No secondary on our hpmr controller
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Meta touch controller profile
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
// touch controllers have no select button we can use
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/system/click"); // right hand system click may not be available
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
|
||||
profile->add_new_binding(ax_touch, "/user/hand/left/input/x/touch,/user/hand/right/input/a/touch");
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
|
||||
profile->add_new_binding(by_touch, "/user/hand/left/input/y/touch,/user/hand/right/input/b/touch");
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); // should be converted to boolean
|
||||
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // should be converted to boolean
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
// primary on our touch controller is our thumbstick
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// touch controller has no secondary input
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
|
||||
// Create our Valve index controller profile
|
||||
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/valve/index_controller");
|
||||
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
|
||||
profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
|
||||
// index controllers have no select button we can use
|
||||
profile->add_new_binding(menu_button, "/user/hand/left/input/system/click,/user/hand/right/input/system/click");
|
||||
profile->add_new_binding(ax_button, "/user/hand/left/input/a/click,/user/hand/right/input/a/click"); // a on both controllers
|
||||
profile->add_new_binding(ax_touch, "/user/hand/left/input/a/touch,/user/hand/right/input/a/touch");
|
||||
profile->add_new_binding(by_button, "/user/hand/left/input/b/click,/user/hand/right/input/b/click"); // b on both controllers
|
||||
profile->add_new_binding(by_touch, "/user/hand/left/input/b/touch,/user/hand/right/input/b/touch");
|
||||
profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
|
||||
profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
|
||||
profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
|
||||
profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
|
||||
profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value"); // this should do a float to bool conversion
|
||||
// primary on our index controller is our thumbstick
|
||||
profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
|
||||
profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
|
||||
profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
|
||||
// secondary on our index controller is our trackpad
|
||||
profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
|
||||
profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/force,/user/hand/right/input/trackpad/force"); // not sure if this will work but doesn't seem to support click...
|
||||
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
|
||||
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
|
||||
add_interaction_profile(profile);
|
||||
}
|
||||
|
||||
void OpenXRActionMap::create_editor_action_sets() {
|
||||
// TODO implement
|
||||
}
|
||||
|
||||
OpenXRActionMap::~OpenXRActionMap() {
|
||||
action_sets.clear();
|
||||
interaction_profiles.clear();
|
||||
}
|
68
modules/openxr/action_map/openxr_action_map.h
Normal file
68
modules/openxr/action_map/openxr_action_map.h
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_action_map.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_ACTION_SETS_H
|
||||
#define OPENXR_ACTION_SETS_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
#include "openxr_action_set.h"
|
||||
#include "openxr_interaction_profile.h"
|
||||
|
||||
class OpenXRActionMap : public Resource {
|
||||
GDCLASS(OpenXRActionMap, Resource);
|
||||
|
||||
private:
|
||||
Array action_sets;
|
||||
Array interaction_profiles;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
void set_action_sets(Array p_action_sets);
|
||||
Array get_action_sets() const;
|
||||
|
||||
void add_action_set(Ref<OpenXRActionSet> p_action_set);
|
||||
void remove_action_set(Ref<OpenXRActionSet> p_action_set);
|
||||
|
||||
void set_interaction_profiles(Array p_interaction_profiles);
|
||||
Array get_interaction_profiles() const;
|
||||
|
||||
void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile);
|
||||
void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile);
|
||||
|
||||
void create_default_action_sets();
|
||||
void create_editor_action_sets();
|
||||
|
||||
~OpenXRActionMap();
|
||||
};
|
||||
|
||||
#endif // !OPENXR_ACTION_SETS_H
|
111
modules/openxr/action_map/openxr_action_set.cpp
Normal file
111
modules/openxr/action_map/openxr_action_set.cpp
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_action_set.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_action_set.h"
|
||||
|
||||
void OpenXRActionSet::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRActionSet::set_localized_name);
|
||||
ClassDB::bind_method(D_METHOD("get_localized_name"), &OpenXRActionSet::get_localized_name);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "localized_name"), "set_localized_name", "get_localized_name");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &OpenXRActionSet::set_priority);
|
||||
ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions);
|
||||
ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("add_action", "action"), &OpenXRActionSet::add_action);
|
||||
ClassDB::bind_method(D_METHOD("remove_action", "action"), &OpenXRActionSet::remove_action);
|
||||
}
|
||||
|
||||
Ref<OpenXRActionSet> OpenXRActionSet::new_action_set(const char *p_name, const char *p_localized_name, const int p_priority) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRActionSet> action_set;
|
||||
action_set.instantiate();
|
||||
action_set->set_name(String(p_name));
|
||||
action_set->set_localized_name(p_localized_name);
|
||||
action_set->set_priority(p_priority);
|
||||
|
||||
return action_set;
|
||||
}
|
||||
|
||||
void OpenXRActionSet::set_localized_name(const String p_localized_name) {
|
||||
localized_name = p_localized_name;
|
||||
}
|
||||
|
||||
String OpenXRActionSet::get_localized_name() const {
|
||||
return localized_name;
|
||||
}
|
||||
|
||||
void OpenXRActionSet::set_priority(const int p_priority) {
|
||||
priority = p_priority;
|
||||
}
|
||||
|
||||
int OpenXRActionSet::get_priority() const {
|
||||
return priority;
|
||||
}
|
||||
|
||||
void OpenXRActionSet::set_actions(Array p_actions) {
|
||||
actions = p_actions;
|
||||
}
|
||||
|
||||
Array OpenXRActionSet::get_actions() const {
|
||||
return actions;
|
||||
}
|
||||
|
||||
void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) {
|
||||
ERR_FAIL_COND(p_action.is_null());
|
||||
|
||||
if (actions.find(p_action) == -1) {
|
||||
actions.push_back(p_action);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) {
|
||||
int idx = actions.find(p_action);
|
||||
if (idx != -1) {
|
||||
actions.remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRAction> new_action = OpenXRAction::new_action(p_name, p_localized_name, p_action_type, p_toplevel_paths);
|
||||
add_action(new_action);
|
||||
return new_action;
|
||||
}
|
||||
|
||||
OpenXRActionSet::~OpenXRActionSet() {
|
||||
actions.clear();
|
||||
}
|
70
modules/openxr/action_map/openxr_action_set.h
Normal file
70
modules/openxr/action_map/openxr_action_set.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_action_set.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_ACTION_SET_H
|
||||
#define OPENXR_ACTION_SET_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
#include "openxr_action.h"
|
||||
|
||||
class OpenXRActionSet : public Resource {
|
||||
GDCLASS(OpenXRActionSet, Resource);
|
||||
|
||||
private:
|
||||
String localized_name;
|
||||
int priority = 0;
|
||||
|
||||
Array actions;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0);
|
||||
|
||||
void set_localized_name(const String p_localized_name);
|
||||
String get_localized_name() const;
|
||||
|
||||
void set_priority(const int p_priority);
|
||||
int get_priority() const;
|
||||
|
||||
void set_actions(Array p_actions);
|
||||
Array get_actions() const;
|
||||
|
||||
void add_action(Ref<OpenXRAction> p_action);
|
||||
void remove_action(Ref<OpenXRAction> p_action);
|
||||
|
||||
Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths);
|
||||
|
||||
~OpenXRActionSet();
|
||||
};
|
||||
|
||||
#endif // !OPENXR_ACTION_SET_H
|
136
modules/openxr/action_map/openxr_interaction_profile.cpp
Normal file
136
modules/openxr/action_map/openxr_interaction_profile.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_interaction_profile.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_interaction_profile.h"
|
||||
|
||||
void OpenXRIPBinding::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_action", "action"), &OpenXRIPBinding::set_action);
|
||||
ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
|
||||
ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths");
|
||||
}
|
||||
|
||||
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRIPBinding> binding;
|
||||
binding.instantiate();
|
||||
binding->set_action(p_action);
|
||||
binding->parse_paths(String(p_paths));
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
void OpenXRIPBinding::set_action(const Ref<OpenXRAction> p_action) {
|
||||
action = p_action;
|
||||
}
|
||||
|
||||
Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
|
||||
return action;
|
||||
}
|
||||
|
||||
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
|
||||
paths = p_paths;
|
||||
}
|
||||
|
||||
PackedStringArray OpenXRIPBinding::get_paths() const {
|
||||
return paths;
|
||||
}
|
||||
|
||||
void OpenXRIPBinding::parse_paths(const String p_paths) {
|
||||
paths = p_paths.split(",", false);
|
||||
}
|
||||
|
||||
OpenXRIPBinding::~OpenXRIPBinding() {
|
||||
action.unref();
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_interaction_profile_path", "interaction_profile_path"), &OpenXRInteractionProfile::set_interaction_profile_path);
|
||||
ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path");
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings);
|
||||
ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings");
|
||||
}
|
||||
|
||||
Ref<OpenXRInteractionProfile> OpenXRInteractionProfile::new_profile(const char *p_input_profile_path) {
|
||||
Ref<OpenXRInteractionProfile> profile;
|
||||
profile.instantiate();
|
||||
profile->set_interaction_profile_path(String(p_input_profile_path));
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::set_interaction_profile_path(const String p_input_profile_path) {
|
||||
interaction_profile_path = p_input_profile_path;
|
||||
}
|
||||
|
||||
String OpenXRInteractionProfile::get_interaction_profile_path() const {
|
||||
return interaction_profile_path;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
|
||||
bindings = p_bindings;
|
||||
}
|
||||
|
||||
Array OpenXRInteractionProfile::get_bindings() const {
|
||||
return bindings;
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
|
||||
ERR_FAIL_COND(p_binding.is_null());
|
||||
|
||||
if (bindings.find(p_binding) == -1) {
|
||||
bindings.push_back(p_binding);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::remove_binding(Ref<OpenXRIPBinding> p_binding) {
|
||||
int idx = bindings.find(p_binding);
|
||||
if (idx != -1) {
|
||||
bindings.remove_at(idx);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
|
||||
// This is a helper function to help build our default action sets
|
||||
|
||||
Ref<OpenXRIPBinding> binding = OpenXRIPBinding::new_binding(p_action, p_paths);
|
||||
add_binding(binding);
|
||||
}
|
||||
|
||||
OpenXRInteractionProfile::~OpenXRInteractionProfile() {
|
||||
bindings.clear();
|
||||
}
|
89
modules/openxr/action_map/openxr_interaction_profile.h
Normal file
89
modules/openxr/action_map/openxr_interaction_profile.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_interaction_profile.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_INTERACTION_PROFILE_H
|
||||
#define OPENXR_INTERACTION_PROFILE_H
|
||||
|
||||
#include "core/io/resource.h"
|
||||
|
||||
#include "openxr_action.h"
|
||||
|
||||
class OpenXRIPBinding : public Resource {
|
||||
GDCLASS(OpenXRIPBinding, Resource);
|
||||
|
||||
private:
|
||||
Ref<OpenXRAction> action;
|
||||
PackedStringArray paths;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths);
|
||||
|
||||
void set_action(const Ref<OpenXRAction> p_action);
|
||||
Ref<OpenXRAction> get_action() const;
|
||||
|
||||
void set_paths(const PackedStringArray p_paths);
|
||||
PackedStringArray get_paths() const;
|
||||
|
||||
void parse_paths(const String p_paths);
|
||||
|
||||
~OpenXRIPBinding();
|
||||
};
|
||||
|
||||
class OpenXRInteractionProfile : public Resource {
|
||||
GDCLASS(OpenXRInteractionProfile, Resource);
|
||||
|
||||
private:
|
||||
String interaction_profile_path;
|
||||
Array bindings;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path);
|
||||
|
||||
void set_interaction_profile_path(const String p_input_profile_path);
|
||||
String get_interaction_profile_path() const;
|
||||
|
||||
void set_bindings(Array p_bindings);
|
||||
Array get_bindings() const;
|
||||
|
||||
void add_binding(Ref<OpenXRIPBinding> p_binding);
|
||||
void remove_binding(Ref<OpenXRIPBinding> p_binding);
|
||||
|
||||
void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths);
|
||||
|
||||
~OpenXRInteractionProfile();
|
||||
};
|
||||
|
||||
#endif // !OPENXR_INTERACTION_PROFILE_H
|
27
modules/openxr/config.py
Normal file
27
modules/openxr/config.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
def can_build(env, platform):
|
||||
if (
|
||||
platform == "linuxbsd" or platform == "windows"
|
||||
): # or platform == "android" -- temporarily disabled android support
|
||||
return env["openxr"]
|
||||
else:
|
||||
# not supported on these platforms
|
||||
return False
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"OpenXRInterface",
|
||||
"OpenXRAction",
|
||||
"OpenXRActionSet",
|
||||
"OpenXRActionMap",
|
||||
"OpenXRInteractionProfile",
|
||||
"OpenXRIPBinding",
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
38
modules/openxr/doc_classes/OpenXRAction.xml
Normal file
38
modules/openxr/doc_classes/OpenXRAction.xml
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRAction" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
An OpenXR action.
|
||||
</brief_description>
|
||||
<description>
|
||||
This resource defines an OpenXR action. Actions can be used both for inputs (buttons/joystick/trigger/etc) and outputs (haptics).
|
||||
OpenXR performs automatic conversion between action type and input type whenever possible. An analogue trigger bound to a boolean action will thus return [code]false[/core] if the trigger is depressed and [code]true[/code] if pressed fully.
|
||||
Actions are not directly bound to specific devices, instead OpenXR recognises a limited number of top level paths that identify devices by usage. We can restrict which devices an action can be bound to by these top level paths. For instance an action that should only be used for hand held controllers can have the top level paths "/user/hand/left" and "/user/hand/right" associated with them. See the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-reserved]reserved path section in the OpenXR specification[/url] for more info on the top level paths.
|
||||
Note that the name of the resource is used to register the action with.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="action_type" type="int" setter="set_action_type" getter="get_action_type" enum="OpenXRAction.ActionType" default="1">
|
||||
The type of action.
|
||||
</member>
|
||||
<member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default="""">
|
||||
The localised description of this action.
|
||||
</member>
|
||||
<member name="toplevel_paths" type="PackedStringArray" setter="set_toplevel_paths" getter="get_toplevel_paths" default="PackedStringArray()">
|
||||
A collections of toplevel paths to which this action can be bound.
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
<constant name="OPENXR_ACTION_BOOL" value="0" enum="ActionType">
|
||||
This action provides a boolean value.
|
||||
</constant>
|
||||
<constant name="OPENXR_ACTION_FLOAT" value="1" enum="ActionType">
|
||||
This action provides a float value between [code]0.0[/code] and [code]1.0[/code] for any analogue input such as triggers.
|
||||
</constant>
|
||||
<constant name="OPENXR_ACTION_VECTOR2" value="2" enum="ActionType">
|
||||
This action provides a vector2 value and can be bound to embedded trackpads and joysticks
|
||||
</constant>
|
||||
<constant name="OPENXR_ACTION_POSE" value="3" enum="ActionType">
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
55
modules/openxr/doc_classes/OpenXRActionMap.xml
Normal file
55
modules/openxr/doc_classes/OpenXRActionMap.xml
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRActionMap" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Collection of [OpenXRActionSet] and [OpenXRInteractionProfile] resources for the OpenXR module.
|
||||
</brief_description>
|
||||
<description>
|
||||
OpenXR uses an action system similar to Godots Input map system to bind inputs and outputs on various types of XR controllers to named actions. OpenXR specifies more detail on these inputs and outputs than Godot supports.
|
||||
Another important distinction is that OpenXR offers no control over these bindings. The bindings we register are suggestions, it is up to the XR runtime to offer users the ability to change these bindings. This allows the XR runtime to fill in the gaps if new hardware becomes available.
|
||||
The action map therefor needs to be loaded at startup and can't be changed afterwards. This resource is a container for the entire action map.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_action_set">
|
||||
<return type="void" />
|
||||
<argument index="0" name="action_set" type="OpenXRActionSet" />
|
||||
<description>
|
||||
Add an action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_interaction_profile">
|
||||
<return type="void" />
|
||||
<argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
|
||||
<description>
|
||||
Add an interaction profile.
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_default_action_sets">
|
||||
<return type="void" />
|
||||
<description>
|
||||
Setup this action set with our default actions.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_action_set">
|
||||
<return type="void" />
|
||||
<argument index="0" name="action_set" type="OpenXRActionSet" />
|
||||
<description>
|
||||
Remove an action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_interaction_profile">
|
||||
<return type="void" />
|
||||
<argument index="0" name="interaction_profile" type="OpenXRInteractionProfile" />
|
||||
<description>
|
||||
Remove an interaction profile.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]">
|
||||
</member>
|
||||
<member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]">
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
40
modules/openxr/doc_classes/OpenXRActionSet.xml
Normal file
40
modules/openxr/doc_classes/OpenXRActionSet.xml
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRActionSet" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Collection of [OpenXRAction] resources that make up an action set.
|
||||
</brief_description>
|
||||
<description>
|
||||
Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle.
|
||||
Action sets can contain the same actions, or actions with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active.
|
||||
Note that the name of the resource is used to identify the action set within OpenXR.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="add_action">
|
||||
<return type="void" />
|
||||
<argument index="0" name="action" type="OpenXRAction" />
|
||||
<description>
|
||||
Add an action to this action set.
|
||||
</description>
|
||||
</method>
|
||||
<method name="remove_action">
|
||||
<return type="void" />
|
||||
<argument index="0" name="action" type="OpenXRAction" />
|
||||
<description>
|
||||
Remove an action from this action set.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="actions" type="Array" setter="set_actions" getter="get_actions" default="[]">
|
||||
Collection of actions for this action set.
|
||||
</member>
|
||||
<member name="localized_name" type="String" setter="set_localized_name" getter="get_localized_name" default="""">
|
||||
The localised name of this action set.
|
||||
</member>
|
||||
<member name="priority" type="int" setter="set_priority" getter="get_priority" default="0">
|
||||
The priority for this action set.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
19
modules/openxr/doc_classes/OpenXRIPBinding.xml
Normal file
19
modules/openxr/doc_classes/OpenXRIPBinding.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRIPBinding" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Defines a binding between an [OpenXRAction] and an XR input or output.
|
||||
</brief_description>
|
||||
<description>
|
||||
This binding resource binds an OpenXR action to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="action" type="OpenXRAction" setter="set_action" getter="get_action">
|
||||
Action that is bound to these paths.
|
||||
</member>
|
||||
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()">
|
||||
Paths that define the inputs or outputs bound on the device.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
20
modules/openxr/doc_classes/OpenXRInteractionProfile.xml
Normal file
20
modules/openxr/doc_classes/OpenXRInteractionProfile.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRInteractionProfile" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Suggested bindings object for OpenXR.
|
||||
</brief_description>
|
||||
<description>
|
||||
This object stores suggested bindings for an interaction profile. Interaction profiles define the meta data for a tracked XR device such as an XR controller.
|
||||
For more information see the [url=https://www.khronos.org/registry/OpenXR/specs/1.0/html/xrspec.html#semantic-path-interaction-profiles]interaction profiles info in the OpenXR specification[/url].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]">
|
||||
Action bindings for this interaction profile.
|
||||
</member>
|
||||
<member name="interaction_profile_path" type="String" setter="set_interaction_profile_path" getter="get_interaction_profile_path" default="""">
|
||||
The interaction profile path identifying the XR device.
|
||||
</member>
|
||||
</members>
|
||||
</class>
|
13
modules/openxr/doc_classes/OpenXRInterface.xml
Normal file
13
modules/openxr/doc_classes/OpenXRInterface.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRInterface" inherits="XRInterface" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
Our OpenXR interface.
|
||||
</brief_description>
|
||||
<description>
|
||||
The OpenXR interface allows Godot to interact with OpenXR runtimes and make it possible to create XR experiences and games.
|
||||
Due to the needs of OpenXR this interface works slightly different then other plugin based XR interfaces. It needs to be initialised when Godot starts. You need to enable OpenXR, settings for this can be found in your games project settings under the XR heading. You do need to mark a viewport for use with XR in order for Godot to know which render result should be output to the headset.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link title="OpenXR documentation">$DOCS_URL/tutorials/vr/openxr/index.html</link>
|
||||
</tutorials>
|
||||
</class>
|
71
modules/openxr/extensions/openxr_android_extension.cpp
Normal file
71
modules/openxr/extensions/openxr_android_extension.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_android_extension.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_android_extension.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
OpenXRAndroidExtension *OpenXRAndroidExtension::singleton = nullptr;
|
||||
|
||||
OpenXRAndroidExtension *OpenXRAndroidExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRAndroidExtension::OpenXRAndroidExtension(OpenXRAPI *p_openxr_api) :
|
||||
OpenXRExtensionWrapper(p_openxr_api) {
|
||||
singleton = this;
|
||||
|
||||
request_extensions[XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME] = nullptr; // must be available
|
||||
|
||||
// Initialize the loader
|
||||
PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
|
||||
result = xrGetInstanceProcAddr(XR_NULL_HANDLE, "xrInitializeLoaderKHR", (PFN_xrVoidFunction *)(&xrInitializeLoaderKHR));
|
||||
ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to retrieve pointer to xrInitializeLoaderKHR");
|
||||
|
||||
// TODO fix this code, this is still code from GDNative!
|
||||
JNIEnv *env = android_api->godot_android_get_env();
|
||||
JavaVM *vm;
|
||||
env->GetJavaVM(&vm);
|
||||
jobject activity_object = env->NewGlobalRef(android_api->godot_android_get_activity());
|
||||
|
||||
XrLoaderInitInfoAndroidKHR loader_init_info_android = {
|
||||
.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR,
|
||||
.next = nullptr,
|
||||
.applicationVM = vm,
|
||||
.applicationContext = activity_object
|
||||
};
|
||||
xrInitializeLoaderKHR((const XrLoaderInitInfoBaseHeaderKHR *)&loader_init_info_android);
|
||||
ERR_FAIL_COND_MSG(XR_FAILED(result), "Failed to call xrInitializeLoaderKHR");
|
||||
}
|
||||
|
||||
OpenXRAndroidExtension::~OpenXRAndroidExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
47
modules/openxr/extensions/openxr_android_extension.h
Normal file
47
modules/openxr/extensions/openxr_android_extension.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_android_extension.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_ANDROID_EXTENSION_H
|
||||
#define OPENXR_ANDROID_EXTENSION_H
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
class OpenXRAndroidExtension : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
static OpenXRAndroidExtension *get_singleton();
|
||||
|
||||
OpenXRAndroidExtension(OpenXRAPI *p_openxr_api);
|
||||
virtual ~OpenXRAndroidExtension() override;
|
||||
|
||||
private:
|
||||
static OpenXRAndroidExtension *singleton;
|
||||
};
|
||||
|
||||
#endif // !OPENXR_ANDROID_EXTENSION_H
|
|
@ -0,0 +1,45 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_composition_layer_provider.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_COMPOSITION_LAYER_PROVIDER_H
|
||||
#define OPENXR_COMPOSITION_LAYER_PROVIDER_H
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
// Interface for OpenXR extensions that provide a composition layer.
|
||||
class OpenXRCompositionLayerProvider {
|
||||
public:
|
||||
// TODO changed to normal method definition for now
|
||||
// CI complains until we implement this, haven't ported it yet from plugin
|
||||
// virtual XrCompositionLayerBaseHeader *get_composition_layer() = 0;
|
||||
XrCompositionLayerBaseHeader *get_composition_layer() { return nullptr; };
|
||||
};
|
||||
|
||||
#endif // OPENXR_COMPOSITION_LAYER_PROVIDER_H
|
106
modules/openxr/extensions/openxr_extension_wrapper.h
Normal file
106
modules/openxr/extensions/openxr_extension_wrapper.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_extension_wrapper.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_EXTENSION_WRAPPER_H
|
||||
#define OPENXR_EXTENSION_WRAPPER_H
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/math/camera_matrix.h"
|
||||
#include "core/templates/map.h"
|
||||
#include "core/templates/rid.h"
|
||||
|
||||
#include "thirdparty/openxr/src/common/xr_linear.h"
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
class OpenXRAPI;
|
||||
|
||||
class OpenXRExtensionWrapper {
|
||||
protected:
|
||||
OpenXRAPI *openxr_api;
|
||||
|
||||
// Store extension we require.
|
||||
// If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available
|
||||
// If bool pointer is set, value will be set to true or false depending on whether extension is available
|
||||
Map<const char *, bool *> request_extensions;
|
||||
|
||||
public:
|
||||
virtual Map<const char *, bool *> get_request_extensions() {
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
// These functions allow an extension to add entries to a struct chain.
|
||||
// `p_next_pointer` points to the last struct that was created for this chain
|
||||
// and should be used as the value for the `pNext` pointer in the first struct you add.
|
||||
// You should return the pointer to the last struct you define as your result.
|
||||
// If you are not adding any structs, just return `p_next_pointer`.
|
||||
// See existing extensions for examples of this implementation.
|
||||
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; }
|
||||
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; }
|
||||
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) { return p_next_pointer; }
|
||||
|
||||
virtual void on_instance_created(const XrInstance p_instance) {}
|
||||
virtual void on_instance_destroyed() {}
|
||||
virtual void on_session_created(const XrSession p_instance) {}
|
||||
virtual void on_process() {}
|
||||
virtual void on_pre_render() {}
|
||||
virtual void on_session_destroyed() {}
|
||||
|
||||
virtual void on_state_idle() {}
|
||||
virtual void on_state_ready() {}
|
||||
virtual void on_state_synchronized() {}
|
||||
virtual void on_state_visible() {}
|
||||
virtual void on_state_focused() {}
|
||||
virtual void on_state_stopping() {}
|
||||
virtual void on_state_loss_pending() {}
|
||||
virtual void on_state_exiting() {}
|
||||
|
||||
// Returns true if the event was handled, false otherwise.
|
||||
virtual bool on_event_polled(const XrEventDataBuffer &event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OpenXRExtensionWrapper(OpenXRAPI *p_openxr_api) { openxr_api = p_openxr_api; };
|
||||
virtual ~OpenXRExtensionWrapper() = default;
|
||||
};
|
||||
|
||||
class OpenXRGraphicsExtensionWrapper : public OpenXRExtensionWrapper {
|
||||
public:
|
||||
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) = 0;
|
||||
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const = 0;
|
||||
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) = 0;
|
||||
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) = 0;
|
||||
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) = 0;
|
||||
virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) = 0;
|
||||
|
||||
OpenXRGraphicsExtensionWrapper(OpenXRAPI *p_openxr_api) :
|
||||
OpenXRExtensionWrapper(p_openxr_api){};
|
||||
};
|
||||
|
||||
#endif // ~OPENXR_EXTENSION_WRAPPER_H
|
695
modules/openxr/extensions/openxr_vulkan_extension.cpp
Normal file
695
modules/openxr/extensions/openxr_vulkan_extension.cpp
Normal file
|
@ -0,0 +1,695 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_vulkan_extension.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "core/string/print_string.h"
|
||||
|
||||
#include "modules/openxr/extensions/openxr_vulkan_extension.h"
|
||||
#include "modules/openxr/openxr_api.h"
|
||||
#include "modules/openxr/openxr_util.h"
|
||||
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
|
||||
#include "servers/rendering/rendering_server_globals.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
// need to include Vulkan so we know of type definitions
|
||||
#define XR_USE_GRAPHICS_API_VULKAN
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
// Including windows.h here is absolutely evil, we shouldn't be doing this outside of platform
|
||||
// however due to the way the openxr headers are put together, we have no choice.
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// include platform dependent structs
|
||||
#include <openxr/openxr_platform.h>
|
||||
|
||||
PFN_xrGetVulkanGraphicsRequirements2KHR xrGetVulkanGraphicsRequirements2KHR_ptr = nullptr;
|
||||
PFN_xrCreateVulkanInstanceKHR xrCreateVulkanInstanceKHR_ptr = nullptr;
|
||||
PFN_xrGetVulkanGraphicsDevice2KHR xrGetVulkanGraphicsDevice2KHR_ptr = nullptr;
|
||||
PFN_xrCreateVulkanDeviceKHR xrCreateVulkanDeviceKHR_ptr = nullptr;
|
||||
|
||||
OpenXRVulkanExtension::OpenXRVulkanExtension(OpenXRAPI *p_openxr_api) :
|
||||
OpenXRGraphicsExtensionWrapper(p_openxr_api) {
|
||||
VulkanContext::set_vulkan_hooks(this);
|
||||
|
||||
request_extensions[XR_KHR_VULKAN_ENABLE2_EXTENSION_NAME] = nullptr; // must be available
|
||||
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
}
|
||||
|
||||
OpenXRVulkanExtension::~OpenXRVulkanExtension() {
|
||||
VulkanContext::set_vulkan_hooks(nullptr);
|
||||
}
|
||||
|
||||
void OpenXRVulkanExtension::on_instance_created(const XrInstance p_instance) {
|
||||
XrResult result;
|
||||
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
|
||||
// Obtain pointers to functions we're accessing here, they are (not yet) part of core.
|
||||
result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsRequirements2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsRequirements2KHR_ptr);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to xrGetVulkanGraphicsRequirements2KHR entry point [", openxr_api->get_error_string(result), "]");
|
||||
}
|
||||
|
||||
result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanInstanceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanInstanceKHR_ptr);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to xrCreateVulkanInstanceKHR entry point [", openxr_api->get_error_string(result), "]");
|
||||
}
|
||||
|
||||
result = xrGetInstanceProcAddr(p_instance, "xrGetVulkanGraphicsDevice2KHR", (PFN_xrVoidFunction *)&xrGetVulkanGraphicsDevice2KHR_ptr);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to xrGetVulkanGraphicsDevice2KHR entry point [", openxr_api->get_error_string(result), "]");
|
||||
}
|
||||
|
||||
result = xrGetInstanceProcAddr(p_instance, "xrCreateVulkanDeviceKHR", (PFN_xrVoidFunction *)&xrCreateVulkanDeviceKHR_ptr);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to xrCreateVulkanDeviceKHR entry point [", openxr_api->get_error_string(result), "]");
|
||||
}
|
||||
}
|
||||
|
||||
XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements) {
|
||||
ERR_FAIL_NULL_V(xrGetVulkanGraphicsRequirements2KHR_ptr, XR_ERROR_HANDLE_INVALID);
|
||||
|
||||
return (*xrGetVulkanGraphicsRequirements2KHR_ptr)(p_instance, p_system_id, p_graphics_requirements);
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::check_graphics_api_support(XrVersion p_desired_version) {
|
||||
ERR_FAIL_NULL_V(openxr_api, false);
|
||||
|
||||
XrGraphicsRequirementsVulkan2KHR vulkan_requirements = {
|
||||
XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN2_KHR, // type
|
||||
nullptr, // next
|
||||
0, // minApiVersionSupported
|
||||
0 // maxApiVersionSupported
|
||||
};
|
||||
|
||||
XrResult result = xrGetVulkanGraphicsRequirements2KHR(openxr_api->get_instance(), openxr_api->get_system_id(), &vulkan_requirements);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to get vulkan graphics requirements [", openxr_api->get_error_string(result), "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
// #ifdef DEBUG
|
||||
print_line("OpenXR: XrGraphicsRequirementsVulkan2KHR:");
|
||||
print_line(" - minApiVersionSupported: ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported));
|
||||
print_line(" - maxApiVersionSupported: ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported));
|
||||
// #endif
|
||||
|
||||
if (p_desired_version < vulkan_requirements.minApiVersionSupported) {
|
||||
print_line("OpenXR: Requested Vulkan version does not meet the minimum version this runtime supports.");
|
||||
print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version));
|
||||
print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported));
|
||||
print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_desired_version > vulkan_requirements.maxApiVersionSupported) {
|
||||
print_line("OpenXR: Requested Vulkan version exceeds the maximum version this runtime has been tested on and is known to support.");
|
||||
print_line("- desired_version ", OpenXRUtil::make_xr_version_string(p_desired_version));
|
||||
print_line("- minApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.minApiVersionSupported));
|
||||
print_line("- maxApiVersionSupported ", OpenXRUtil::make_xr_version_string(vulkan_requirements.maxApiVersionSupported));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XrResult OpenXRVulkanExtension::xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result) {
|
||||
ERR_FAIL_NULL_V(xrCreateVulkanInstanceKHR_ptr, XR_ERROR_HANDLE_INVALID);
|
||||
|
||||
return (*xrCreateVulkanInstanceKHR_ptr)(p_instance, p_create_info, r_vulkan_instance, r_vulkan_result);
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance) {
|
||||
// get the vulkan version we are creating
|
||||
uint32_t vulkan_version = p_vulkan_create_info->pApplicationInfo->apiVersion;
|
||||
uint32_t major_version = VK_VERSION_MAJOR(vulkan_version);
|
||||
uint32_t minor_version = VK_VERSION_MINOR(vulkan_version);
|
||||
uint32_t patch_version = VK_VERSION_PATCH(vulkan_version);
|
||||
XrVersion desired_version = XR_MAKE_VERSION(major_version, minor_version, patch_version);
|
||||
|
||||
// check if this is supported
|
||||
if (!check_graphics_api_support(desired_version)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XrVulkanInstanceCreateInfoKHR xr_vulkan_instance_info = {
|
||||
XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR, // type
|
||||
nullptr, // next
|
||||
openxr_api->get_system_id(), // systemId
|
||||
0, // createFlags
|
||||
vkGetInstanceProcAddr, // pfnGetInstanceProcAddr
|
||||
p_vulkan_create_info, // vulkanCreateInfo
|
||||
nullptr, // vulkanAllocator
|
||||
};
|
||||
|
||||
VkResult vk_result = VK_SUCCESS;
|
||||
XrResult result = xrCreateVulkanInstanceKHR(openxr_api->get_instance(), &xr_vulkan_instance_info, &vulkan_instance, &vk_result);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to create vulkan instance [", openxr_api->get_error_string(result), "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(vk_result == VK_ERROR_INCOMPATIBLE_DRIVER, false,
|
||||
"Cannot find a compatible Vulkan installable client driver (ICD).\n\n"
|
||||
"vkCreateInstance Failure");
|
||||
ERR_FAIL_COND_V_MSG(vk_result == VK_ERROR_EXTENSION_NOT_PRESENT, false,
|
||||
"Cannot find a specified extension library.\n"
|
||||
"Make sure your layers path is set appropriately.\n"
|
||||
"vkCreateInstance Failure");
|
||||
ERR_FAIL_COND_V_MSG(vk_result, false,
|
||||
"vkCreateInstance failed.\n\n"
|
||||
"Do you have a compatible Vulkan installable client driver (ICD) installed?\n"
|
||||
"Please look at the Getting Started guide for additional information.\n"
|
||||
"vkCreateInstance Failure");
|
||||
|
||||
*r_instance = vulkan_instance;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XrResult OpenXRVulkanExtension::xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device) {
|
||||
ERR_FAIL_NULL_V(xrGetVulkanGraphicsDevice2KHR_ptr, XR_ERROR_HANDLE_INVALID);
|
||||
|
||||
return (*xrGetVulkanGraphicsDevice2KHR_ptr)(p_instance, p_get_info, r_vulkan_physical_device);
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::get_physical_device(VkPhysicalDevice *r_device) {
|
||||
ERR_FAIL_NULL_V(openxr_api, false);
|
||||
|
||||
XrVulkanGraphicsDeviceGetInfoKHR get_info = {
|
||||
XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR, // type
|
||||
nullptr, // next
|
||||
openxr_api->get_system_id(), // systemId
|
||||
vulkan_instance, // vulkanInstance
|
||||
};
|
||||
|
||||
XrResult result = xrGetVulkanGraphicsDevice2KHR(openxr_api->get_instance(), &get_info, &vulkan_physical_device);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to obtain vulkan physical device [", openxr_api->get_error_string(result), "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
*r_device = vulkan_physical_device;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XrResult OpenXRVulkanExtension::xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result) {
|
||||
ERR_FAIL_NULL_V(xrCreateVulkanDeviceKHR_ptr, XR_ERROR_HANDLE_INVALID);
|
||||
|
||||
return (*xrCreateVulkanDeviceKHR_ptr)(p_instance, p_create_info, r_device, r_result);
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device) {
|
||||
ERR_FAIL_NULL_V(openxr_api, false);
|
||||
|
||||
// the first entry in our queue list should be the one we need to remember...
|
||||
vulkan_queue_family_index = p_device_create_info->pQueueCreateInfos[0].queueFamilyIndex;
|
||||
vulkan_queue_index = 0; // ??
|
||||
|
||||
XrVulkanDeviceCreateInfoKHR create_info = {
|
||||
XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR, // type
|
||||
nullptr, // next
|
||||
openxr_api->get_system_id(), // systemId
|
||||
0, // createFlags
|
||||
vkGetInstanceProcAddr, // pfnGetInstanceProcAddr
|
||||
vulkan_physical_device, // vulkanPhysicalDevice
|
||||
p_device_create_info, // vulkanCreateInfo
|
||||
nullptr // vulkanAllocator
|
||||
};
|
||||
|
||||
VkResult vk_result = VK_SUCCESS;
|
||||
XrResult result = xrCreateVulkanDeviceKHR(openxr_api->get_instance(), &create_info, &vulkan_device, &vk_result);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to create vulkan device [", openxr_api->get_error_string(result), "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vk_result != VK_SUCCESS) {
|
||||
print_line("OpenXR: Failed to create vulkan device [vulkan error", vk_result, "]");
|
||||
}
|
||||
|
||||
*r_device = vulkan_device;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
XrGraphicsBindingVulkanKHR OpenXRVulkanExtension::graphics_binding_vulkan;
|
||||
|
||||
void *OpenXRVulkanExtension::set_session_create_and_get_next_pointer(void *p_next_pointer) {
|
||||
graphics_binding_vulkan.type = XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR;
|
||||
graphics_binding_vulkan.next = p_next_pointer;
|
||||
graphics_binding_vulkan.instance = vulkan_instance;
|
||||
graphics_binding_vulkan.physicalDevice = vulkan_physical_device;
|
||||
graphics_binding_vulkan.device = vulkan_device;
|
||||
graphics_binding_vulkan.queueFamilyIndex = vulkan_queue_family_index;
|
||||
graphics_binding_vulkan.queueIndex = vulkan_queue_index;
|
||||
|
||||
return &graphics_binding_vulkan;
|
||||
}
|
||||
|
||||
void OpenXRVulkanExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
|
||||
// We might want to do more here especially if we keep things in linear color space
|
||||
// Possibly add in R10G10B10A2 as an option if we're using the mobile renderer.
|
||||
p_usable_swap_chains.push_back(VK_FORMAT_R8G8B8A8_SRGB);
|
||||
p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_SRGB);
|
||||
p_usable_swap_chains.push_back(VK_FORMAT_R8G8B8A8_UINT);
|
||||
p_usable_swap_chains.push_back(VK_FORMAT_B8G8R8A8_UINT);
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
|
||||
XrSwapchainImageVulkanKHR *images = nullptr;
|
||||
|
||||
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(rendering_server, false);
|
||||
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
|
||||
ERR_FAIL_NULL_V(rendering_device, false);
|
||||
|
||||
uint32_t swapchain_length;
|
||||
XrResult result = xrEnumerateSwapchainImages(p_swapchain, 0, &swapchain_length, nullptr);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to get swapchaim image count [", openxr_api->get_error_string(result), "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
images = (XrSwapchainImageVulkanKHR *)memalloc(sizeof(XrSwapchainImageVulkanKHR) * swapchain_length);
|
||||
ERR_FAIL_NULL_V_MSG(images, false, "OpenXR Couldn't allocate memory for swap chain image");
|
||||
|
||||
for (uint64_t i = 0; i < swapchain_length; i++) {
|
||||
images[i].type = XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR;
|
||||
images[i].next = nullptr;
|
||||
images[i].image = nullptr;
|
||||
}
|
||||
|
||||
result = xrEnumerateSwapchainImages(p_swapchain, swapchain_length, &swapchain_length, (XrSwapchainImageBaseHeader *)images);
|
||||
if (XR_FAILED(result)) {
|
||||
print_line("OpenXR: Failed to get swapchaim images [", openxr_api->get_error_string(result), "]");
|
||||
memfree(images);
|
||||
return false;
|
||||
}
|
||||
|
||||
// SwapchainGraphicsData *data = (SwapchainGraphicsData *)memalloc(sizeof(SwapchainGraphicsData));
|
||||
SwapchainGraphicsData *data = memnew(SwapchainGraphicsData);
|
||||
if (data == nullptr) {
|
||||
print_line("OpenXR: Failed to allocate memory for swapchain data");
|
||||
memfree(images);
|
||||
return false;
|
||||
}
|
||||
*r_swapchain_graphics_data = data;
|
||||
data->is_multiview = (p_array_size > 1);
|
||||
|
||||
RenderingDevice::DataFormat format = RenderingDevice::DATA_FORMAT_R8G8B8A8_SRGB; // TODO set this based on p_swapchain_format
|
||||
RenderingDevice::TextureSamples samples = RenderingDevice::TEXTURE_SAMPLES_1; // TODO set this based on p_sample_count
|
||||
uint64_t usage_flags = RenderingDevice::TEXTURE_USAGE_SAMPLING_BIT | RenderingDevice::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
|
||||
Vector<RID> image_rids;
|
||||
Vector<RID> framebuffers;
|
||||
|
||||
// create Godot texture objects for each entry in our swapchain
|
||||
for (uint64_t i = 0; i < swapchain_length; i++) {
|
||||
RID image_rid = rendering_device->texture_create_from_extension(
|
||||
p_array_size == 1 ? RenderingDevice::TEXTURE_TYPE_2D : RenderingDevice::TEXTURE_TYPE_2D_ARRAY,
|
||||
format,
|
||||
samples,
|
||||
usage_flags,
|
||||
(uint64_t)images[i].image,
|
||||
p_width,
|
||||
p_height,
|
||||
1,
|
||||
p_array_size);
|
||||
|
||||
image_rids.push_back(image_rid);
|
||||
|
||||
{
|
||||
Vector<RID> fb;
|
||||
fb.push_back(image_rid);
|
||||
|
||||
RID fb_rid = rendering_device->framebuffer_create(fb, RenderingDevice::INVALID_ID, p_array_size);
|
||||
framebuffers.push_back(fb_rid);
|
||||
}
|
||||
}
|
||||
|
||||
data->image_rids = image_rids;
|
||||
data->framebuffers = framebuffers;
|
||||
|
||||
memfree(images);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) {
|
||||
// Even though this is a Vulkan renderer we're using OpenGL coordinate systems
|
||||
XrMatrix4x4f matrix;
|
||||
XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far);
|
||||
|
||||
for (int j = 0; j < 4; j++) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
r_camera_matrix.matrix[j][i] = matrix.m[j * 4 + i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) {
|
||||
SwapchainGraphicsData *data = (SwapchainGraphicsData *)p_swapchain_graphics_data;
|
||||
ERR_FAIL_NULL_V(data, false);
|
||||
ERR_FAIL_COND_V(p_from_render_target.is_null(), false);
|
||||
ERR_FAIL_NULL_V(RendererStorageRD::base_singleton, false);
|
||||
|
||||
RID source_image = RendererStorageRD::base_singleton->render_target_get_rd_texture(p_from_render_target);
|
||||
ERR_FAIL_COND_V(source_image.is_null(), false);
|
||||
|
||||
RID depth_image; // TODO implement
|
||||
|
||||
ERR_FAIL_INDEX_V(p_image_index, data->framebuffers.size(), false);
|
||||
RID fb = data->framebuffers[p_image_index];
|
||||
ERR_FAIL_COND_V(fb.is_null(), false);
|
||||
|
||||
// Our vulkan extension can only be used in conjunction with our vulkan renderer.
|
||||
// We need access to the effects object in order to have access to our copy logic.
|
||||
// Breaking all the rules but there is no nice way to do this.
|
||||
EffectsRD *effects = RendererStorageRD::base_singleton->get_effects();
|
||||
ERR_FAIL_NULL_V(effects, false);
|
||||
effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OpenXRVulkanExtension::cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) {
|
||||
if (*p_swapchain_graphics_data == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapchainGraphicsData *data = (SwapchainGraphicsData *)*p_swapchain_graphics_data;
|
||||
|
||||
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
||||
ERR_FAIL_NULL(rendering_server);
|
||||
RenderingDevice *rendering_device = rendering_server->get_rendering_device();
|
||||
ERR_FAIL_NULL(rendering_device);
|
||||
|
||||
for (int i = 0; i < data->image_rids.size(); i++) {
|
||||
// This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain
|
||||
rendering_device->free(data->image_rids[i]);
|
||||
}
|
||||
data->image_rids.clear();
|
||||
|
||||
for (int i = 0; i < data->framebuffers.size(); i++) {
|
||||
// This should clean up our RIDs and associated texture objects but shouldn't destroy the images, they are owned by our XrSwapchain
|
||||
rendering_device->free(data->framebuffers[i]);
|
||||
}
|
||||
data->framebuffers.clear();
|
||||
|
||||
memdelete(data);
|
||||
*p_swapchain_graphics_data = nullptr;
|
||||
}
|
||||
|
||||
#define ENUM_TO_STRING_CASE(e) \
|
||||
case e: { \
|
||||
return String(#e); \
|
||||
} break;
|
||||
|
||||
String OpenXRVulkanExtension::get_swapchain_format_name(int64_t p_swapchain_format) const {
|
||||
// This really should be in vulkan_context...
|
||||
VkFormat format = VkFormat(p_swapchain_format);
|
||||
switch (format) {
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_UNDEFINED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R4G4_UNORM_PACK8)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R4G4B4A4_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B4G4R4A4_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R5G6B5_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B5G6R5_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R5G5B5A1_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B5G5R5A1_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A1R5G5B5_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8_SRGB)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8_SRGB)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8_SRGB)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8_SRGB)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R8G8B8A8_SRGB)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8A8_SRGB)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_UNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_USCALED_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SSCALED_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_UINT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SINT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A8B8G8R8_SRGB_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_UNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_USCALED_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SSCALED_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_UINT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2R10G10B10_SINT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_UNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_USCALED_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SSCALED_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_UINT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A2B10G10R10_SINT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_USCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SSCALED)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R16G16B16A16_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R32G32B32A32_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_SINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R64G64B64A64_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B10G11R11_UFLOAT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_D16_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_X8_D24_UNORM_PACK32)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_D32_SFLOAT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_S8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_D16_UNORM_S8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_D24_UNORM_S8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_D32_SFLOAT_S8_UINT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGB_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGB_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGBA_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC1_RGBA_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC2_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC2_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC3_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC3_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC4_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC4_SNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC5_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC5_SNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC6H_UFLOAT_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC6H_SFLOAT_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC7_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_BC7_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11_SNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11G11_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_EAC_R11G11_SNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_UNORM_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_SRGB_BLOCK)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8B8G8R8_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B8G8R8G8_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_420_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R10X6_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R10X6G10X6_UNORM_2PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R12X4_UNORM_PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R12X4G12X4_UNORM_2PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16B16G16R16_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_B16G16R16G16_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_420_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_422_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT)
|
||||
ENUM_TO_STRING_CASE(VK_FORMAT_MAX_ENUM)
|
||||
default: {
|
||||
return String("Swapchain format ") + String::num_int64(int64_t(p_swapchain_format));
|
||||
} break;
|
||||
}
|
||||
}
|
93
modules/openxr/extensions/openxr_vulkan_extension.h
Normal file
93
modules/openxr/extensions/openxr_vulkan_extension.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_vulkan_extension.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_VULKAN_EXTENSION_H
|
||||
#define OPENXR_VULKAN_EXTENSION_H
|
||||
|
||||
#include "core/templates/vector.h"
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
#include "drivers/vulkan/vulkan_context.h"
|
||||
|
||||
// Forward declare these so we don't need OpenXR headers where-ever this is included
|
||||
// Including OpenXR at this point gives loads and loads of compile issues especially
|
||||
// on Windows because windows.h is EVIL and really shouldn't be included outside of platform
|
||||
// but we really don't have a choice in the matter
|
||||
|
||||
struct XrGraphicsRequirementsVulkanKHR;
|
||||
struct XrVulkanInstanceCreateInfoKHR;
|
||||
struct XrVulkanGraphicsDeviceGetInfoKHR;
|
||||
struct XrVulkanDeviceCreateInfoKHR;
|
||||
struct XrGraphicsBindingVulkanKHR;
|
||||
|
||||
class OpenXRVulkanExtension : public OpenXRGraphicsExtensionWrapper, VulkanHooks {
|
||||
public:
|
||||
OpenXRVulkanExtension(OpenXRAPI *p_openxr_api);
|
||||
virtual ~OpenXRVulkanExtension() override;
|
||||
|
||||
virtual void on_instance_created(const XrInstance p_instance) override;
|
||||
virtual void *set_session_create_and_get_next_pointer(void *p_next_pointer) override;
|
||||
|
||||
virtual bool create_vulkan_instance(const VkInstanceCreateInfo *p_vulkan_create_info, VkInstance *r_instance);
|
||||
virtual bool get_physical_device(VkPhysicalDevice *r_device);
|
||||
virtual bool create_vulkan_device(const VkDeviceCreateInfo *p_device_create_info, VkDevice *r_device);
|
||||
|
||||
virtual void get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) override;
|
||||
virtual String get_swapchain_format_name(int64_t p_swapchain_format) const override;
|
||||
virtual bool get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) override;
|
||||
virtual void cleanup_swapchain_graphics_data(void **p_swapchain_graphics_data) override;
|
||||
virtual bool create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, CameraMatrix &r_camera_matrix) override;
|
||||
virtual bool copy_render_target_to_image(RID p_from_render_target, void *p_swapchain_graphics_data, int p_image_index) override;
|
||||
|
||||
private:
|
||||
static OpenXRVulkanExtension *singleton;
|
||||
static XrGraphicsBindingVulkanKHR graphics_binding_vulkan; // declaring this as static so we don't need to know its size and we only need it once when creating our session
|
||||
|
||||
struct SwapchainGraphicsData {
|
||||
bool is_multiview;
|
||||
Vector<RID> image_rids;
|
||||
Vector<RID> framebuffers;
|
||||
};
|
||||
|
||||
bool check_graphics_api_support(XrVersion p_desired_version);
|
||||
|
||||
VkInstance vulkan_instance;
|
||||
VkPhysicalDevice vulkan_physical_device;
|
||||
VkDevice vulkan_device;
|
||||
uint32_t vulkan_queue_family_index;
|
||||
uint32_t vulkan_queue_index;
|
||||
|
||||
XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements);
|
||||
XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result);
|
||||
XrResult xrGetVulkanGraphicsDevice2KHR(XrInstance p_instance, const XrVulkanGraphicsDeviceGetInfoKHR *p_get_info, VkPhysicalDevice *r_vulkan_physical_device);
|
||||
XrResult xrCreateVulkanDeviceKHR(XrInstance p_instance, const XrVulkanDeviceCreateInfoKHR *p_create_info, VkDevice *r_device, VkResult *r_result);
|
||||
};
|
||||
|
||||
#endif // !OPENXR_VULKAN_EXTENSION_H
|
2171
modules/openxr/openxr_api.cpp
Normal file
2171
modules/openxr/openxr_api.cpp
Normal file
File diff suppressed because it is too large
Load diff
261
modules/openxr/openxr_api.h
Normal file
261
modules/openxr/openxr_api.h
Normal file
|
@ -0,0 +1,261 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_api.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_DRIVER_H
|
||||
#define OPENXR_DRIVER_H
|
||||
|
||||
#include "core/error/error_macros.h"
|
||||
#include "core/math/camera_matrix.h"
|
||||
#include "core/math/transform_3d.h"
|
||||
#include "core/math/vector2.h"
|
||||
#include "core/os/memory.h"
|
||||
#include "core/string/ustring.h"
|
||||
#include "core/templates/map.h"
|
||||
#include "core/templates/rid_owner.h"
|
||||
#include "core/templates/vector.h"
|
||||
#include "servers/xr/xr_pose.h"
|
||||
|
||||
#include "thirdparty/openxr/src/common/xr_linear.h"
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
#include "action_map/openxr_action.h"
|
||||
|
||||
#include "extensions/openxr_composition_layer_provider.h"
|
||||
#include "extensions/openxr_extension_wrapper.h"
|
||||
|
||||
// Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initialising structs which ensures zeroing out unspecified members.
|
||||
// Godot is currently restricted to C++17 which doesn't allow this notation. Make sure critical fields are set.
|
||||
|
||||
// forward declarations, we don't want to include these fully
|
||||
class OpenXRVulkanExtension;
|
||||
|
||||
class OpenXRAPI {
|
||||
private:
|
||||
// our singleton
|
||||
static OpenXRAPI *singleton;
|
||||
|
||||
// layers
|
||||
uint32_t num_layer_properties = 0;
|
||||
XrApiLayerProperties *layer_properties = nullptr;
|
||||
|
||||
// extensions
|
||||
uint32_t num_supported_extensions = 0;
|
||||
XrExtensionProperties *supported_extensions = nullptr;
|
||||
Vector<OpenXRExtensionWrapper *> registered_extension_wrappers;
|
||||
Vector<const char *> enabled_extensions;
|
||||
|
||||
// composition layer providers
|
||||
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
|
||||
|
||||
// view configuration
|
||||
uint32_t num_view_configuration_types = 0;
|
||||
XrViewConfigurationType *supported_view_configuration_types = nullptr;
|
||||
|
||||
// reference spaces
|
||||
uint32_t num_reference_spaces = 0;
|
||||
XrReferenceSpaceType *supported_reference_spaces = nullptr;
|
||||
|
||||
// swapchains (note these are platform dependent)
|
||||
uint32_t num_swapchain_formats = 0;
|
||||
int64_t *supported_swapchain_formats = nullptr;
|
||||
|
||||
// configuration
|
||||
XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
||||
XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
||||
XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
|
||||
XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
||||
|
||||
// state
|
||||
XrInstance instance = XR_NULL_HANDLE;
|
||||
XrSystemId system_id;
|
||||
String system_name;
|
||||
uint32_t vendor_id;
|
||||
XrSystemTrackingProperties tracking_properties;
|
||||
XrSession session = XR_NULL_HANDLE;
|
||||
XrSessionState session_state = XR_SESSION_STATE_UNKNOWN;
|
||||
bool running = false;
|
||||
XrFrameState frame_state = { XR_TYPE_FRAME_STATE, NULL, 0, 0, false };
|
||||
|
||||
OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr;
|
||||
XrSystemGraphicsProperties graphics_properties;
|
||||
void *swapchain_graphics_data = nullptr;
|
||||
uint32_t image_index = 0;
|
||||
bool image_acquired = false;
|
||||
|
||||
uint32_t view_count = 0;
|
||||
XrViewConfigurationView *view_configuration_views = nullptr;
|
||||
XrView *views = nullptr;
|
||||
XrCompositionLayerProjectionView *projection_views = nullptr;
|
||||
XrSwapchain swapchain = XR_NULL_HANDLE;
|
||||
|
||||
XrSpace play_space = XR_NULL_HANDLE;
|
||||
XrSpace view_space = XR_NULL_HANDLE;
|
||||
bool view_pose_valid = false;
|
||||
XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
|
||||
|
||||
bool load_layer_properties();
|
||||
bool load_supported_extensions();
|
||||
bool is_extension_supported(const char *p_extension) const;
|
||||
|
||||
// instance
|
||||
bool create_instance();
|
||||
bool get_system_info();
|
||||
bool load_supported_view_configuration_types();
|
||||
bool is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const;
|
||||
bool load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type);
|
||||
void destroy_instance();
|
||||
|
||||
// session
|
||||
bool create_session();
|
||||
bool load_supported_reference_spaces();
|
||||
bool is_reference_space_supported(XrReferenceSpaceType p_reference_space);
|
||||
bool setup_spaces();
|
||||
bool load_supported_swapchain_formats();
|
||||
bool is_swapchain_format_supported(int64_t p_swapchain_format);
|
||||
bool create_main_swapchain();
|
||||
void destroy_session();
|
||||
|
||||
// swapchains
|
||||
bool create_swapchain(int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, XrSwapchain &r_swapchain, void **r_swapchain_graphics_data);
|
||||
bool acquire_image(XrSwapchain p_swapchain, uint32_t &r_image_index);
|
||||
bool release_image(XrSwapchain p_swapchain);
|
||||
|
||||
// action map
|
||||
struct Path {
|
||||
XrPath path;
|
||||
};
|
||||
RID_Owner<Path, true> xr_path_owner;
|
||||
|
||||
struct ActionSet {
|
||||
bool is_attached;
|
||||
XrActionSet handle;
|
||||
};
|
||||
RID_Owner<ActionSet, true> action_set_owner;
|
||||
|
||||
struct PathWithSpace {
|
||||
XrPath toplevel_path;
|
||||
XrSpace space;
|
||||
bool was_location_valid;
|
||||
};
|
||||
|
||||
struct Action {
|
||||
XrActionType action_type;
|
||||
Vector<PathWithSpace> toplevel_paths;
|
||||
XrAction handle;
|
||||
};
|
||||
RID_Owner<Action, true> action_owner;
|
||||
|
||||
// state changes
|
||||
bool poll_events();
|
||||
bool on_state_idle();
|
||||
bool on_state_ready();
|
||||
bool on_state_synchronized();
|
||||
bool on_state_visible();
|
||||
bool on_state_focused();
|
||||
bool on_state_stopping();
|
||||
bool on_state_loss_pending();
|
||||
bool on_state_exiting();
|
||||
|
||||
// convencience
|
||||
void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len);
|
||||
|
||||
protected:
|
||||
friend class OpenXRVulkanExtension;
|
||||
|
||||
XrInstance get_instance() const { return instance; };
|
||||
XrSystemId get_system_id() const { return system_id; };
|
||||
XrSession get_session() const { return session; };
|
||||
|
||||
// helper method to convert an XrPosef to a Transform3D
|
||||
Transform3D transform_from_pose(const XrPosef &p_pose);
|
||||
|
||||
// helper method to get a valid Transform3D from an openxr space location
|
||||
XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform);
|
||||
XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform);
|
||||
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity);
|
||||
|
||||
public:
|
||||
static void setup_global_defs();
|
||||
static bool openxr_is_enabled();
|
||||
static OpenXRAPI *get_singleton();
|
||||
|
||||
String get_error_string(XrResult result);
|
||||
String get_swapchain_format_name(int64_t p_swapchain_format) const;
|
||||
|
||||
void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
|
||||
|
||||
bool is_initialized();
|
||||
bool is_running();
|
||||
bool initialise(const String &p_rendering_driver);
|
||||
bool initialise_session();
|
||||
void finish();
|
||||
|
||||
XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; };
|
||||
bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; };
|
||||
|
||||
Size2 get_recommended_target_size();
|
||||
XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
|
||||
bool get_view_transform(uint32_t p_view, Transform3D &r_transform);
|
||||
bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix);
|
||||
bool process();
|
||||
|
||||
void pre_render();
|
||||
bool pre_draw_viewport(RID p_render_target);
|
||||
void post_draw_viewport(RID p_render_target);
|
||||
void end_frame();
|
||||
|
||||
// action map
|
||||
String get_default_action_map_resource_name();
|
||||
RID path_create(const String p_name);
|
||||
void path_free(RID p_path);
|
||||
RID action_set_create(const String p_name, const String p_localized_name, const int p_priority);
|
||||
bool action_set_attach(RID p_action_set);
|
||||
void action_set_free(RID p_action_set);
|
||||
RID action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_toplevel_paths);
|
||||
void action_free(RID p_action);
|
||||
|
||||
struct Binding {
|
||||
RID action;
|
||||
String path;
|
||||
};
|
||||
bool suggest_bindings(const String p_interaction_profile, const Vector<Binding> p_bindings);
|
||||
|
||||
bool sync_action_sets(const Vector<RID> p_active_sets);
|
||||
bool get_action_bool(RID p_action, RID p_path);
|
||||
float get_action_float(RID p_action, RID p_path);
|
||||
Vector2 get_action_vector2(RID p_action, RID p_path);
|
||||
XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_path, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
|
||||
bool trigger_haptic_pulse(RID p_action, RID p_path, float p_frequency, float p_amplitude, XrDuration p_duration_ns);
|
||||
|
||||
OpenXRAPI();
|
||||
~OpenXRAPI();
|
||||
};
|
||||
|
||||
#endif // !OPENXR_DRIVER_H
|
663
modules/openxr/openxr_interface.cpp
Normal file
663
modules/openxr/openxr_interface.cpp
Normal file
|
@ -0,0 +1,663 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_interface.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_interface.h"
|
||||
|
||||
#include "core/io/resource_loader.h"
|
||||
#include "core/io/resource_saver.h"
|
||||
#include "servers/rendering/rendering_server_globals.h"
|
||||
|
||||
void OpenXRInterface::_bind_methods() {
|
||||
// todo
|
||||
}
|
||||
|
||||
StringName OpenXRInterface::get_name() const {
|
||||
return StringName("OpenXR");
|
||||
};
|
||||
|
||||
uint32_t OpenXRInterface::get_capabilities() const {
|
||||
return XRInterface::XR_VR + XRInterface::XR_STEREO;
|
||||
};
|
||||
|
||||
XRInterface::TrackingStatus OpenXRInterface::get_tracking_status() const {
|
||||
return tracking_state;
|
||||
}
|
||||
|
||||
void OpenXRInterface::_load_action_map() {
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
|
||||
// This may seem a bit duplicitous to a little bit of background info here.
|
||||
// OpenXRActionMap (with all its sub resource classes) is a class that allows us to configure and store an action map in.
|
||||
// This gives the user the ability to edit the action map in a UI and customise the actions.
|
||||
// OpenXR however requires us to submit an action map and it takes over from that point and we can no longer change it.
|
||||
// This system does that push and we store the info needed to then work with this action map going forward.
|
||||
|
||||
// Within our openxr device we maintain a number of classes that wrap the relevant OpenXR objects for this.
|
||||
// Within OpenXRInterface we have a few internal classes that keep track of what we've created.
|
||||
// This allow us to process the relevant actions each frame.
|
||||
|
||||
// just in case clean up
|
||||
free_action_sets();
|
||||
free_trackers();
|
||||
|
||||
Ref<OpenXRActionMap> action_map;
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
action_map.instantiate();
|
||||
action_map->create_editor_action_sets();
|
||||
#endif
|
||||
} else {
|
||||
String default_tres_name = openxr_api->get_default_action_map_resource_name();
|
||||
|
||||
// Check if we can load our default
|
||||
if (ResourceLoader::exists(default_tres_name)) {
|
||||
action_map = ResourceLoader::load(default_tres_name);
|
||||
}
|
||||
|
||||
// Check if we need to create default action set
|
||||
if (action_map.is_null()) {
|
||||
action_map.instantiate();
|
||||
action_map->create_default_action_sets();
|
||||
#ifdef TOOLS_ENABLED
|
||||
// Save our action sets so our user can
|
||||
action_map->set_path(default_tres_name, true);
|
||||
ResourceSaver::save(default_tres_name, action_map);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// process our action map
|
||||
if (action_map.is_valid()) {
|
||||
Map<Ref<OpenXRAction>, RID> action_rids;
|
||||
|
||||
Array action_sets = action_map->get_action_sets();
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
// Create our action set
|
||||
Ref<OpenXRActionSet> xr_action_set = action_sets[i];
|
||||
ActionSet *action_set = create_action_set(xr_action_set->get_name(), xr_action_set->get_localized_name(), xr_action_set->get_priority());
|
||||
if (!action_set) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now create our actions for these
|
||||
Array actions = xr_action_set->get_actions();
|
||||
for (int j = 0; j < actions.size(); j++) {
|
||||
Ref<OpenXRAction> xr_action = actions[j];
|
||||
|
||||
PackedStringArray toplevel_paths = xr_action->get_toplevel_paths();
|
||||
Vector<RID> toplevel_rids;
|
||||
Vector<Tracker *> trackers;
|
||||
|
||||
for (int k = 0; k < toplevel_paths.size(); k++) {
|
||||
Tracker *tracker = get_tracker(toplevel_paths[k]);
|
||||
if (tracker) {
|
||||
toplevel_rids.push_back(tracker->path_rid);
|
||||
trackers.push_back(tracker);
|
||||
}
|
||||
}
|
||||
|
||||
Action *action = create_action(action_set, xr_action->get_name(), xr_action->get_localized_name(), xr_action->get_action_type(), toplevel_rids);
|
||||
if (action) {
|
||||
// we link our actions back to our trackers so we know which actions to check when we're processing our trackers
|
||||
for (int t = 0; t < trackers.size(); t++) {
|
||||
link_action_to_tracker(trackers[t], action);
|
||||
}
|
||||
|
||||
// add this to our map for creating our interaction profiles
|
||||
action_rids[xr_action] = action->action_rid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now do our suggestions
|
||||
Array interaction_profiles = action_map->get_interaction_profiles();
|
||||
for (int i = 0; i < interaction_profiles.size(); i++) {
|
||||
Vector<OpenXRAPI::Binding> bindings;
|
||||
Ref<OpenXRInteractionProfile> xr_interaction_profile = interaction_profiles[i];
|
||||
|
||||
Array xr_bindings = xr_interaction_profile->get_bindings();
|
||||
for (int j = 0; j < xr_bindings.size(); j++) {
|
||||
Ref<OpenXRIPBinding> xr_binding = xr_bindings[j];
|
||||
Ref<OpenXRAction> xr_action = xr_binding->get_action();
|
||||
OpenXRAPI::Binding binding;
|
||||
|
||||
if (action_rids.has(xr_action)) {
|
||||
binding.action = action_rids[xr_action];
|
||||
} else {
|
||||
print_line("Action ", xr_action->get_name(), " isn't part of an action set!");
|
||||
continue;
|
||||
}
|
||||
|
||||
PackedStringArray xr_paths = xr_binding->get_paths();
|
||||
for (int k = 0; k < xr_paths.size(); k++) {
|
||||
binding.path = xr_paths[k];
|
||||
bindings.push_back(binding);
|
||||
}
|
||||
}
|
||||
|
||||
openxr_api->suggest_bindings(xr_interaction_profile->get_interaction_profile_path(), bindings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRInterface::ActionSet *OpenXRInterface::create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority) {
|
||||
ERR_FAIL_NULL_V(openxr_api, nullptr);
|
||||
|
||||
// find if it already exists
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
if (action_sets[i]->action_set_name == p_action_set_name) {
|
||||
// already exists in this set
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ActionSet *action_set = memnew(ActionSet);
|
||||
action_set->action_set_name = p_action_set_name;
|
||||
action_set->is_active = true;
|
||||
action_set->action_set_rid = openxr_api->action_set_create(p_action_set_name, p_localized_name, p_priority);
|
||||
action_sets.push_back(action_set);
|
||||
|
||||
return action_set;
|
||||
}
|
||||
|
||||
void OpenXRInterface::free_action_sets() {
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
ActionSet *action_set = action_sets[i];
|
||||
|
||||
openxr_api->path_free(action_set->action_set_rid);
|
||||
free_actions(action_set);
|
||||
|
||||
memfree(action_set);
|
||||
}
|
||||
action_sets.clear();
|
||||
}
|
||||
|
||||
OpenXRInterface::Action *OpenXRInterface::create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> p_toplevel_paths) {
|
||||
ERR_FAIL_NULL_V(openxr_api, nullptr);
|
||||
|
||||
for (int i = 0; i < p_action_set->actions.size(); i++) {
|
||||
if (p_action_set->actions[i]->action_name == p_action_name) {
|
||||
// already exists in this set
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Action *action = memnew(Action);
|
||||
action->action_name = p_action_name;
|
||||
action->action_type = p_action_type;
|
||||
action->action_rid = openxr_api->action_create(p_action_set->action_set_rid, p_action_name, p_localized_name, p_action_type, p_toplevel_paths);
|
||||
p_action_set->actions.push_back(action);
|
||||
|
||||
return action;
|
||||
}
|
||||
|
||||
OpenXRInterface::Action *OpenXRInterface::find_action(const String &p_action_name) {
|
||||
// We just find the first action by this name
|
||||
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
for (int j = 0; j < action_sets[i]->actions.size(); j++) {
|
||||
if (action_sets[i]->actions[j]->action_name == p_action_name) {
|
||||
return action_sets[i]->actions[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void OpenXRInterface::free_actions(ActionSet *p_action_set) {
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
|
||||
for (int i = 0; i < p_action_set->actions.size(); i++) {
|
||||
Action *action = p_action_set->actions[i];
|
||||
|
||||
openxr_api->action_free(action->action_rid);
|
||||
|
||||
memdelete(action);
|
||||
}
|
||||
p_action_set->actions.clear();
|
||||
}
|
||||
|
||||
OpenXRInterface::Tracker *OpenXRInterface::get_tracker(const String &p_path_name) {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(xr_server, nullptr);
|
||||
ERR_FAIL_NULL_V(openxr_api, nullptr);
|
||||
|
||||
Tracker *tracker = nullptr;
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
tracker = trackers[i];
|
||||
if (tracker->path_name == p_path_name) {
|
||||
return tracker;
|
||||
}
|
||||
}
|
||||
|
||||
// create our positional tracker
|
||||
Ref<XRPositionalTracker> positional_tracker;
|
||||
positional_tracker.instantiate();
|
||||
|
||||
// We have standardised some names to make things nicer to the user so lets recognise the toplevel paths related to these.
|
||||
if (p_path_name == "/user/hand/left") {
|
||||
positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
|
||||
positional_tracker->set_tracker_name("left_hand");
|
||||
positional_tracker->set_tracker_desc("Left hand controller");
|
||||
positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
|
||||
} else if (p_path_name == "/user/hand/right") {
|
||||
positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
|
||||
positional_tracker->set_tracker_name("right_hand");
|
||||
positional_tracker->set_tracker_desc("Right hand controller");
|
||||
positional_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
|
||||
} else {
|
||||
positional_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
|
||||
positional_tracker->set_tracker_name(p_path_name);
|
||||
positional_tracker->set_tracker_desc(p_path_name);
|
||||
}
|
||||
xr_server->add_tracker(positional_tracker);
|
||||
|
||||
// create a new entry
|
||||
tracker = memnew(Tracker);
|
||||
tracker->path_name = p_path_name;
|
||||
tracker->path_rid = openxr_api->path_create(p_path_name);
|
||||
tracker->positional_tracker = positional_tracker;
|
||||
trackers.push_back(tracker);
|
||||
|
||||
return tracker;
|
||||
}
|
||||
|
||||
OpenXRInterface::Tracker *OpenXRInterface::find_tracker(const String &p_positional_tracker_name) {
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
Tracker *tracker = trackers[i];
|
||||
if (tracker->positional_tracker.is_valid() && tracker->positional_tracker->get_tracker_name() == p_positional_tracker_name) {
|
||||
return tracker;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void OpenXRInterface::link_action_to_tracker(Tracker *p_tracker, Action *p_action) {
|
||||
if (p_tracker->actions.find(p_action) == -1) {
|
||||
p_tracker->actions.push_back(p_action);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInterface::handle_tracker(Tracker *p_tracker) {
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
ERR_FAIL_COND(p_tracker->positional_tracker.is_null());
|
||||
|
||||
// handle all the actions
|
||||
for (int i = 0; i < p_tracker->actions.size(); i++) {
|
||||
Action *action = p_tracker->actions[i];
|
||||
switch (action->action_type) {
|
||||
case OpenXRAction::OPENXR_ACTION_BOOL: {
|
||||
bool pressed = openxr_api->get_action_bool(action->action_rid, p_tracker->path_rid);
|
||||
p_tracker->positional_tracker->set_input(action->action_name, Variant(pressed));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_FLOAT: {
|
||||
real_t value = openxr_api->get_action_float(action->action_rid, p_tracker->path_rid);
|
||||
p_tracker->positional_tracker->set_input(action->action_name, Variant(value));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_VECTOR2: {
|
||||
Vector2 value = openxr_api->get_action_vector2(action->action_rid, p_tracker->path_rid);
|
||||
p_tracker->positional_tracker->set_input(action->action_name, Variant(value));
|
||||
} break;
|
||||
case OpenXRAction::OPENXR_ACTION_POSE: {
|
||||
Transform3D transform;
|
||||
Vector3 linear, angular;
|
||||
XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(action->action_rid, p_tracker->path_rid, transform, linear, angular);
|
||||
if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) {
|
||||
String name;
|
||||
// We can't have dual action names in OpenXR hence we added _pose, but default, aim and grip and default pose action names in Godot so rename them on the tracker.
|
||||
// NOTE need to decide on whether we should keep the naming convention or rename it on Godots side
|
||||
if (action->action_name == "default_pose") {
|
||||
name = "default";
|
||||
} else if (action->action_name == "aim_pose") {
|
||||
name = "aim";
|
||||
} else if (action->action_name == "grip_pose") {
|
||||
name = "grip";
|
||||
} else {
|
||||
name = action->action_name;
|
||||
}
|
||||
p_tracker->positional_tracker->set_pose(name, transform, linear, angular, confidence);
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
// not yet supported
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
Action *action = find_action(p_action_name);
|
||||
ERR_FAIL_NULL(action);
|
||||
Tracker *tracker = find_tracker(p_tracker_name);
|
||||
ERR_FAIL_NULL(tracker);
|
||||
|
||||
// TODO OpenXR does not support delay, so we may need to add support for that somehow...
|
||||
|
||||
XrDuration duration = XrDuration(p_duration_sec * 1000000000.0); // seconds -> nanoseconds
|
||||
|
||||
openxr_api->trigger_haptic_pulse(action->action_rid, tracker->path_rid, p_frequency, p_amplitude, duration);
|
||||
}
|
||||
|
||||
void OpenXRInterface::free_trackers() {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
ERR_FAIL_NULL(xr_server);
|
||||
ERR_FAIL_NULL(openxr_api);
|
||||
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
Tracker *tracker = trackers[i];
|
||||
|
||||
openxr_api->path_free(tracker->path_rid);
|
||||
xr_server->remove_tracker(tracker->positional_tracker);
|
||||
tracker->positional_tracker.unref();
|
||||
|
||||
memdelete(tracker);
|
||||
}
|
||||
trackers.clear();
|
||||
}
|
||||
|
||||
bool OpenXRInterface::initialise_on_startup() const {
|
||||
if (openxr_api == nullptr) {
|
||||
return false;
|
||||
} else if (!openxr_api->is_initialized()) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXRInterface::is_initialized() const {
|
||||
return initialized;
|
||||
};
|
||||
|
||||
bool OpenXRInterface::initialize() {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(xr_server, false);
|
||||
|
||||
if (openxr_api == nullptr) {
|
||||
return false;
|
||||
} else if (!openxr_api->is_initialized()) {
|
||||
return false;
|
||||
} else if (initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// load up our action sets before setting up our session, note that our profiles are suggestions, OpenXR takes ownership of (re)binding
|
||||
_load_action_map();
|
||||
|
||||
if (!openxr_api->initialise_session()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// we must create a tracker for our head
|
||||
head.instantiate();
|
||||
head->set_tracker_type(XRServer::TRACKER_HEAD);
|
||||
head->set_tracker_name("head");
|
||||
head->set_tracker_desc("Players head");
|
||||
xr_server->add_tracker(head);
|
||||
|
||||
// attach action sets
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
openxr_api->action_set_attach(action_sets[i]->action_set_rid);
|
||||
}
|
||||
|
||||
// make this our primary interface
|
||||
xr_server->set_primary_interface(this);
|
||||
|
||||
initialized = true;
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
void OpenXRInterface::uninitialize() {
|
||||
// Our OpenXR driver will clean itself up properly when Godot exits, so we just do some basic stuff here
|
||||
|
||||
// end the session if we need to?
|
||||
|
||||
// cleanup stuff
|
||||
free_action_sets();
|
||||
free_trackers();
|
||||
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
if (xr_server) {
|
||||
if (head.is_valid()) {
|
||||
xr_server->remove_tracker(head);
|
||||
|
||||
head.unref();
|
||||
}
|
||||
}
|
||||
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
bool OpenXRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
XRInterface::PlayAreaMode OpenXRInterface::get_play_area_mode() const {
|
||||
return XRInterface::XR_PLAY_AREA_UNKNOWN;
|
||||
}
|
||||
|
||||
bool OpenXRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Size2 OpenXRInterface::get_render_target_size() {
|
||||
if (openxr_api == nullptr) {
|
||||
return Size2();
|
||||
} else {
|
||||
return openxr_api->get_recommended_target_size();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t OpenXRInterface::get_view_count() {
|
||||
// TODO set this based on our configuration
|
||||
return 2;
|
||||
}
|
||||
|
||||
void OpenXRInterface::_set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye) {
|
||||
p_transform = Transform3D();
|
||||
|
||||
// if we're not tracking, don't put our head on the floor...
|
||||
p_transform.origin.y = 1.5 * p_world_scale;
|
||||
|
||||
// overkill but..
|
||||
if (p_eye == 1) {
|
||||
p_transform.origin.x = 0.03 * p_world_scale;
|
||||
} else if (p_eye == 2) {
|
||||
p_transform.origin.x = -0.03 * p_world_scale;
|
||||
}
|
||||
}
|
||||
|
||||
Transform3D OpenXRInterface::get_camera_transform() {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(xr_server, Transform3D());
|
||||
|
||||
Transform3D hmd_transform;
|
||||
double world_scale = xr_server->get_world_scale();
|
||||
|
||||
// head_transform should be updated in process
|
||||
|
||||
hmd_transform.basis = head_transform.basis;
|
||||
hmd_transform.origin = head_transform.origin * world_scale;
|
||||
|
||||
return hmd_transform;
|
||||
}
|
||||
|
||||
Transform3D OpenXRInterface::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
ERR_FAIL_NULL_V(xr_server, Transform3D());
|
||||
|
||||
Transform3D t;
|
||||
if (openxr_api && openxr_api->get_view_transform(p_view, t)) {
|
||||
// update our cached value if we have a valid transform
|
||||
transform_for_view[p_view] = t;
|
||||
} else {
|
||||
// reuse cached value
|
||||
t = transform_for_view[p_view];
|
||||
}
|
||||
|
||||
// Apply our world scale
|
||||
double world_scale = xr_server->get_world_scale();
|
||||
t.origin *= world_scale;
|
||||
|
||||
return p_cam_transform * xr_server->get_reference_frame() * t;
|
||||
}
|
||||
|
||||
CameraMatrix OpenXRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
|
||||
CameraMatrix cm;
|
||||
|
||||
if (openxr_api) {
|
||||
if (openxr_api->get_view_projection(p_view, p_z_near, p_z_far, cm)) {
|
||||
return cm;
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to get from our OpenXR device? Default to some sort of sensible camera matrix..
|
||||
cm.set_for_hmd(p_view + 1, 1.0, 6.0, 14.5, 4.0, 1.5, p_z_near, p_z_far);
|
||||
|
||||
return cm;
|
||||
}
|
||||
|
||||
void OpenXRInterface::process() {
|
||||
if (openxr_api) {
|
||||
// do our normal process
|
||||
if (openxr_api->process()) {
|
||||
Transform3D t;
|
||||
Vector3 linear_velocity;
|
||||
Vector3 angular_velocity;
|
||||
XRPose::TrackingConfidence confidence = openxr_api->get_head_center(t, linear_velocity, angular_velocity);
|
||||
if (confidence != XRPose::XR_TRACKING_CONFIDENCE_NONE) {
|
||||
// Only update our transform if we have one to update it with
|
||||
// note that poses are stored without world scale and reference frame applied!
|
||||
head_transform = t;
|
||||
head_linear_velocity = linear_velocity;
|
||||
head_angular_velocity = angular_velocity;
|
||||
}
|
||||
}
|
||||
|
||||
// handle our action sets....
|
||||
Vector<RID> active_sets;
|
||||
for (int i = 0; i < action_sets.size(); i++) {
|
||||
if (action_sets[i]->is_active) {
|
||||
active_sets.push_back(action_sets[i]->action_set_rid);
|
||||
}
|
||||
}
|
||||
|
||||
if (openxr_api->sync_action_sets(active_sets)) {
|
||||
for (int i = 0; i < trackers.size(); i++) {
|
||||
handle_tracker(trackers[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (head.is_valid()) {
|
||||
// TODO figure out how to get our velocities
|
||||
|
||||
head->set_pose("default", head_transform, head_linear_velocity, head_angular_velocity);
|
||||
|
||||
// TODO set confidence on pose once we support tracking this..
|
||||
}
|
||||
}
|
||||
|
||||
void OpenXRInterface::pre_render() {
|
||||
if (openxr_api) {
|
||||
openxr_api->pre_render();
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXRInterface::pre_draw_viewport(RID p_render_target) {
|
||||
if (openxr_api) {
|
||||
return openxr_api->pre_draw_viewport(p_render_target);
|
||||
} else {
|
||||
// don't render
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Vector<BlitToScreen> OpenXRInterface::post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) {
|
||||
Vector<BlitToScreen> blit_to_screen;
|
||||
|
||||
// If separate HMD we should output one eye to screen
|
||||
if (p_screen_rect != Rect2()) {
|
||||
BlitToScreen blit;
|
||||
|
||||
blit.render_target = p_render_target;
|
||||
blit.multi_view.use_layer = true;
|
||||
blit.multi_view.layer = 0;
|
||||
blit.lens_distortion.apply = false;
|
||||
|
||||
Size2 render_size = get_render_target_size();
|
||||
Rect2 dst_rect = p_screen_rect;
|
||||
float new_height = dst_rect.size.x * (render_size.y / render_size.x);
|
||||
if (new_height > dst_rect.size.y) {
|
||||
dst_rect.position.y = (0.5 * dst_rect.size.y) - (0.5 * new_height);
|
||||
dst_rect.size.y = new_height;
|
||||
} else {
|
||||
float new_width = dst_rect.size.y * (render_size.x / render_size.y);
|
||||
|
||||
dst_rect.position.x = (0.5 * dst_rect.size.x) - (0.5 * new_width);
|
||||
dst_rect.size.x = new_width;
|
||||
}
|
||||
|
||||
blit.dst_rect = dst_rect;
|
||||
blit_to_screen.push_back(blit);
|
||||
}
|
||||
|
||||
if (openxr_api) {
|
||||
openxr_api->post_draw_viewport(p_render_target);
|
||||
}
|
||||
|
||||
return blit_to_screen;
|
||||
}
|
||||
|
||||
void OpenXRInterface::end_frame() {
|
||||
if (openxr_api) {
|
||||
openxr_api->end_frame();
|
||||
}
|
||||
}
|
||||
|
||||
OpenXRInterface::OpenXRInterface() {
|
||||
openxr_api = OpenXRAPI::get_singleton();
|
||||
|
||||
// while we don't have head tracking, don't put the headset on the floor...
|
||||
_set_default_pos(head_transform, 1.0, 0);
|
||||
_set_default_pos(transform_for_view[0], 1.0, 1);
|
||||
_set_default_pos(transform_for_view[1], 1.0, 2);
|
||||
}
|
||||
|
||||
OpenXRInterface::~OpenXRInterface() {
|
||||
openxr_api = nullptr;
|
||||
}
|
129
modules/openxr/openxr_interface.h
Normal file
129
modules/openxr/openxr_interface.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_interface.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_INTERFACE_H
|
||||
#define OPENXR_INTERFACE_H
|
||||
|
||||
#include "servers/xr/xr_interface.h"
|
||||
#include "servers/xr/xr_positional_tracker.h"
|
||||
|
||||
#include "action_map/openxr_action_map.h"
|
||||
#include "openxr_api.h"
|
||||
|
||||
class OpenXRInterface : public XRInterface {
|
||||
GDCLASS(OpenXRInterface, XRInterface);
|
||||
|
||||
private:
|
||||
OpenXRAPI *openxr_api = nullptr;
|
||||
bool initialized = false;
|
||||
XRInterface::TrackingStatus tracking_state;
|
||||
|
||||
// At a minimum we need a tracker for our head
|
||||
Ref<XRPositionalTracker> head;
|
||||
Transform3D head_transform;
|
||||
Vector3 head_linear_velocity;
|
||||
Vector3 head_angular_velocity;
|
||||
Transform3D transform_for_view[2]; // We currently assume 2, but could be 4 for VARJO which we do not support yet
|
||||
|
||||
void _load_action_map();
|
||||
|
||||
struct Action {
|
||||
String action_name;
|
||||
OpenXRAction::ActionType action_type;
|
||||
RID action_rid;
|
||||
};
|
||||
struct ActionSet {
|
||||
String action_set_name;
|
||||
bool is_active;
|
||||
RID action_set_rid;
|
||||
Vector<Action *> actions;
|
||||
};
|
||||
struct Tracker {
|
||||
String path_name;
|
||||
RID path_rid;
|
||||
Ref<XRPositionalTracker> positional_tracker;
|
||||
Vector<Action *> actions;
|
||||
};
|
||||
|
||||
Vector<ActionSet *> action_sets;
|
||||
Vector<Tracker *> trackers;
|
||||
|
||||
ActionSet *create_action_set(const String &p_action_set_name, const String &p_localized_name, const int p_priority);
|
||||
void free_action_sets();
|
||||
|
||||
Action *create_action(ActionSet *p_action_set, const String &p_action_name, const String &p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> p_toplevel_paths);
|
||||
Action *find_action(const String &p_action_name);
|
||||
void free_actions(ActionSet *p_action_set);
|
||||
|
||||
Tracker *get_tracker(const String &p_path_name);
|
||||
Tracker *find_tracker(const String &p_positional_tracker_name);
|
||||
void link_action_to_tracker(Tracker *p_tracker, Action *p_action);
|
||||
void handle_tracker(Tracker *p_tracker);
|
||||
void free_trackers();
|
||||
|
||||
void _set_default_pos(Transform3D &p_transform, double p_world_scale, uint64_t p_eye);
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual StringName get_name() const override;
|
||||
virtual uint32_t get_capabilities() const override;
|
||||
|
||||
virtual TrackingStatus get_tracking_status() const override;
|
||||
|
||||
bool initialise_on_startup() const;
|
||||
virtual bool is_initialized() const override;
|
||||
virtual bool initialize() override;
|
||||
virtual void uninitialize() override;
|
||||
|
||||
virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0) override;
|
||||
|
||||
virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
|
||||
virtual XRInterface::PlayAreaMode get_play_area_mode() const override;
|
||||
virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override;
|
||||
|
||||
virtual Size2 get_render_target_size() override;
|
||||
virtual uint32_t get_view_count() override;
|
||||
virtual Transform3D get_camera_transform() override;
|
||||
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
|
||||
virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
|
||||
|
||||
virtual void process() override;
|
||||
virtual void pre_render() override;
|
||||
bool pre_draw_viewport(RID p_render_target) override;
|
||||
virtual Vector<BlitToScreen> post_draw_viewport(RID p_render_target, const Rect2 &p_screen_rect) override;
|
||||
virtual void end_frame() override;
|
||||
|
||||
OpenXRInterface();
|
||||
~OpenXRInterface();
|
||||
};
|
||||
|
||||
#endif // !OPENXR_INTERFACE_H
|
291
modules/openxr/openxr_util.cpp
Normal file
291
modules/openxr/openxr_util.cpp
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_util.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "openxr_util.h"
|
||||
|
||||
#define ENUM_TO_STRING_CASE(e) \
|
||||
case e: { \
|
||||
return String(#e); \
|
||||
} break;
|
||||
|
||||
// TODO see if we can generate this code further using the xml file with meta data supplied by OpenXR
|
||||
|
||||
String OpenXRUtil::get_view_configuration_name(XrViewConfigurationType p_view_configuration) {
|
||||
switch (p_view_configuration) {
|
||||
ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO)
|
||||
ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO)
|
||||
ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_PRIMARY_QUAD_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_SECONDARY_MONO_FIRST_PERSON_OBSERVER_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_VIEW_CONFIGURATION_TYPE_MAX_ENUM)
|
||||
default: {
|
||||
return String("View Configuration ") + String::num_int64(int64_t(p_view_configuration));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
String OpenXRUtil::get_reference_space_name(XrReferenceSpaceType p_reference_space) {
|
||||
switch (p_reference_space) {
|
||||
ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_VIEW)
|
||||
ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_LOCAL)
|
||||
ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_STAGE)
|
||||
ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_UNBOUNDED_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_COMBINED_EYE_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_REFERENCE_SPACE_TYPE_MAX_ENUM)
|
||||
default: {
|
||||
return String("Reference space ") + String::num_int64(int64_t(p_reference_space));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
String OpenXRUtil::get_structure_type_name(XrStructureType p_structure_type) {
|
||||
switch (p_structure_type) {
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_UNKNOWN)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_API_LAYER_PROPERTIES)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EXTENSION_PROPERTIES)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_GET_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_PROPERTIES)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_LOCATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SESSION_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SESSION_BEGIN_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_STATE)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FRAME_END_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAPTIC_VIBRATION)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_BUFFER)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_BOOLEAN)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_FLOAT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_VECTOR2F)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_POSE)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_SET_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_PROPERTIES)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FRAME_WAIT_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PROJECTION)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_QUAD)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_REFERENCE_SPACE_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_SPACE_CREATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_VIEW)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPACE_LOCATION)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPACE_VELOCITY)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FRAME_STATE)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_PROPERTIES)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FRAME_BEGIN_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_EVENTS_LOST)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_STATE)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTION_STATE_GET_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAPTIC_ACTION_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SESSION_ACTION_SETS_ATTACH_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ACTIONS_SYNC_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INPUT_SOURCE_LOCALIZED_NAME_GET_INFO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_CUBE_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_SWAPCHAIN_FORMAT_LIST_CREATE_INFO_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_PERF_SETTINGS_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_EQUIRECT_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_DEBUG_UTILS_LABEL_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_WIN32_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_XLIB_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_XCB_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_WAYLAND_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_OPENGL_ES_ANDROID_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_OPENGL_ES_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_OPENGL_ES_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_VULKAN_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_VULKAN_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_VULKAN_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_D3D11_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_D3D11_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D11_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_D3D12_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_D3D12_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_REQUIREMENTS_D3D12_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EYE_GAZE_SAMPLE_TIME_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VISIBILITY_MASK_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_VISIBILITY_MASK_CHANGED_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SESSION_CREATE_INFO_OVERLAY_EXTX)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_MAIN_SESSION_VISIBILITY_CHANGED_EXTX)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_COLOR_SCALE_BIAS_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_SPACE_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_IMAGE_LAYOUT_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_ALPHA_BLEND_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_DEPTH_RANGE_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GRAPHICS_BINDING_EGL_MNDX)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_GRAPH_NODE_SPACE_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINTS_LOCATE_INFO_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINT_LOCATIONS_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINT_VELOCITIES_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_HAND_TRACKING_MESH_PROPERTIES_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_SPACE_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_UPDATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_MESH_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_POSE_TYPE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SESSION_BEGIN_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_STATE_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_STATE_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_FRAME_END_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_LAYER_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SECONDARY_VIEW_CONFIGURATION_SWAPCHAIN_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_KEY_STATE_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_NODE_PROPERTIES_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_PROPERTIES_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_NODE_STATE_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_CONTROLLER_MODEL_STATE_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_CONFIGURATION_VIEW_FOV_EPIC)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HOLOGRAPHIC_WINDOW_ATTACHMENT_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_REPROJECTION_PLANE_OVERRIDE_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_ANDROID_SURFACE_SWAPCHAIN_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_SECURE_CONTENT_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_INTERACTION_PROFILE_ANALOG_THRESHOLD_VALVE)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_JOINTS_MOTION_RANGE_INFO_EXT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_INSTANCE_CREATE_INFO_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_DEVICE_CREATE_INFO_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VULKAN_GRAPHICS_DEVICE_GET_INFO_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_EQUIRECT2_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBSERVER_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_NEW_SCENE_COMPUTE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VISUAL_MESH_COMPUTE_LOD_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_GET_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENT_LOCATIONS_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENTS_LOCATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBJECTS_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_COMPONENT_PARENT_FILTER_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_OBJECT_TYPES_FILTER_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_PLANES_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_PLANE_ALIGNMENT_FILTER_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESHES_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_BUFFERS_GET_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_BUFFERS_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_VERTEX_BUFFER_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_INDICES_UINT32_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_MESH_INDICES_UINT16_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SERIALIZED_SCENE_FRAGMENT_DATA_GET_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SCENE_DESERIALIZE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_DISPLAY_REFRESH_RATE_CHANGED_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIVE_TRACKER_PATHS_HTCX)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_COLOR_SPACE_PROPERTIES_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_MESH_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_SCALE_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_AIM_STATE_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_HAND_TRACKING_CAPSULES_STATE_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_CREATE_INFO_FOVEATION_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_TRIANGLE_MESH_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GEOMETRY_INSTANCE_CREATE_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_GEOMETRY_INSTANCE_TRANSFORM_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_STYLE_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_RGBA_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_PASSTHROUGH_COLOR_MAP_MONO_TO_MONO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_PASSTHROUGH_STATE_CHANGED_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_BINDING_MODIFICATIONS_KHR)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_VIEW_LOCATE_FOVEATED_RENDERING_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_FOVEATED_VIEW_CONFIGURATION_VIEW_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_FOVEATED_RENDERING_PROPERTIES_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_DEPTH_TEST_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_MARKER_TRACKING_PROPERTIES_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_EVENT_DATA_MARKER_TRACKING_UPDATE_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_MARKER_SPACE_CREATE_INFO_VARJO)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_PERSISTENCE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SPATIAL_ANCHOR_FROM_PERSISTED_ANCHOR_CREATE_INFO_MSFT)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_IMAGE_FOVEATION_VULKAN_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_ANDROID_SURFACE_DIMENSIONS_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_OPENGL_ES_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SWAPCHAIN_STATE_SAMPLER_VULKAN_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_COMPOSITION_LAYER_SPACE_WARP_INFO_FB)
|
||||
ENUM_TO_STRING_CASE(XR_TYPE_SYSTEM_SPACE_WARP_PROPERTIES_FB)
|
||||
ENUM_TO_STRING_CASE(XR_STRUCTURE_TYPE_MAX_ENUM)
|
||||
default: {
|
||||
return String("Structure type ") + String::num_int64(int64_t(p_structure_type));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
String OpenXRUtil::get_session_state_name(XrSessionState p_session_state) {
|
||||
switch (p_session_state) {
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_UNKNOWN)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_IDLE)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_READY)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_SYNCHRONIZED)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_VISIBLE)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_FOCUSED)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_STOPPING)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_LOSS_PENDING)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_EXITING)
|
||||
ENUM_TO_STRING_CASE(XR_SESSION_STATE_MAX_ENUM)
|
||||
default: {
|
||||
return String("Session state ") + String::num_int64(int64_t(p_session_state));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
String OpenXRUtil::make_xr_version_string(XrVersion p_version) {
|
||||
String version;
|
||||
|
||||
version += String::num_int64(XR_VERSION_MAJOR(p_version));
|
||||
version += String(".");
|
||||
version += String::num_int64(XR_VERSION_MINOR(p_version));
|
||||
version += String(".");
|
||||
version += String::num_int64(XR_VERSION_PATCH(p_version));
|
||||
|
||||
return version;
|
||||
}
|
46
modules/openxr/openxr_util.h
Normal file
46
modules/openxr/openxr_util.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*************************************************************************/
|
||||
/* openxr_util.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_UTIL_H
|
||||
#define OPENXR_UTIL_H
|
||||
|
||||
#include "core/string/ustring.h"
|
||||
#include <openxr/openxr.h>
|
||||
|
||||
class OpenXRUtil {
|
||||
public:
|
||||
static String get_view_configuration_name(XrViewConfigurationType p_view_configuration);
|
||||
static String get_reference_space_name(XrReferenceSpaceType p_reference_space);
|
||||
static String get_structure_type_name(XrStructureType p_structure_type);
|
||||
static String get_session_state_name(XrSessionState p_session_state);
|
||||
static String make_xr_version_string(XrVersion p_version);
|
||||
};
|
||||
|
||||
#endif // !OPENXR_UTIL_H
|
91
modules/openxr/register_types.cpp
Normal file
91
modules/openxr/register_types.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*************************************************************************/
|
||||
/* register_types.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
#include "main/main.h"
|
||||
|
||||
#include "openxr_interface.h"
|
||||
|
||||
#include "action_map/openxr_action.h"
|
||||
#include "action_map/openxr_action_map.h"
|
||||
#include "action_map/openxr_action_set.h"
|
||||
#include "action_map/openxr_interaction_profile.h"
|
||||
|
||||
OpenXRAPI *openxr_api = nullptr;
|
||||
Ref<OpenXRInterface> openxr_interface;
|
||||
|
||||
void preregister_openxr_types() {
|
||||
// For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon.
|
||||
|
||||
OpenXRAPI::setup_global_defs();
|
||||
openxr_api = OpenXRAPI::get_singleton();
|
||||
if (openxr_api) {
|
||||
if (!openxr_api->initialise(Main::get_rendering_driver_name())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void register_openxr_types() {
|
||||
GDREGISTER_CLASS(OpenXRInterface);
|
||||
|
||||
GDREGISTER_CLASS(OpenXRAction);
|
||||
GDREGISTER_CLASS(OpenXRActionSet);
|
||||
GDREGISTER_CLASS(OpenXRActionMap);
|
||||
GDREGISTER_CLASS(OpenXRIPBinding);
|
||||
GDREGISTER_CLASS(OpenXRInteractionProfile);
|
||||
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
if (xr_server) {
|
||||
openxr_interface.instantiate();
|
||||
xr_server->add_interface(openxr_interface);
|
||||
|
||||
if (openxr_interface->initialise_on_startup()) {
|
||||
openxr_interface->initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unregister_openxr_types() {
|
||||
if (openxr_interface.is_valid()) {
|
||||
// unregister our interface from the XR server
|
||||
if (XRServer::get_singleton()) {
|
||||
XRServer::get_singleton()->remove_interface(openxr_interface);
|
||||
}
|
||||
|
||||
// and release
|
||||
openxr_interface.unref();
|
||||
}
|
||||
|
||||
if (openxr_api) {
|
||||
openxr_api->finish();
|
||||
memdelete(openxr_api);
|
||||
}
|
||||
}
|
40
modules/openxr/register_types.h
Normal file
40
modules/openxr/register_types.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
#ifndef OPENXR_REGISTER_TYPES_H
|
||||
#define OPENXR_REGISTER_TYPES_H
|
||||
|
||||
#define MODULE_OPENXR_HAS_PREREGISTER
|
||||
|
||||
void preregister_openxr_types();
|
||||
void register_openxr_types();
|
||||
void unregister_openxr_types();
|
||||
|
||||
#endif // OPENXR_REGISTER_TYPES_H
|
|
@ -448,11 +448,6 @@ void XRController3D::_bind_methods() {
|
|||
|
||||
ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble);
|
||||
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
|
||||
ADD_PROPERTY_DEFAULT("rumble", 0.0);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name")));
|
||||
ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name")));
|
||||
ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
|
||||
|
@ -558,20 +553,6 @@ Vector2 XRController3D::get_axis(const StringName &p_name) const {
|
|||
}
|
||||
}
|
||||
|
||||
real_t XRController3D::get_rumble() const {
|
||||
if (!tracker.is_valid()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return tracker->get_rumble();
|
||||
}
|
||||
|
||||
void XRController3D::set_rumble(real_t p_rumble) {
|
||||
if (tracker.is_valid()) {
|
||||
tracker->set_rumble(p_rumble);
|
||||
}
|
||||
}
|
||||
|
||||
XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
|
||||
// get our XRServer
|
||||
if (!tracker.is_valid()) {
|
||||
|
@ -612,7 +593,7 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const {
|
|||
}
|
||||
}
|
||||
|
||||
bool xr_enabled = GLOBAL_GET("rendering/xr/enabled");
|
||||
bool xr_enabled = GLOBAL_GET("xr/shaders/enabled");
|
||||
if (!xr_enabled) {
|
||||
warnings.push_back(TTR("XR is not enabled in rendering project settings. Stereoscopic output is not supported unless this is enabled."));
|
||||
}
|
||||
|
|
|
@ -139,9 +139,6 @@ public:
|
|||
float get_value(const StringName &p_name) const;
|
||||
Vector2 get_axis(const StringName &p_name) const;
|
||||
|
||||
real_t get_rumble() const;
|
||||
void set_rumble(real_t p_rumble);
|
||||
|
||||
XRPositionalTracker::TrackerHand get_tracker_hand() const;
|
||||
|
||||
XRController3D() {}
|
||||
|
|
|
@ -45,7 +45,7 @@ bool RendererCompositor::is_xr_enabled() const {
|
|||
}
|
||||
|
||||
RendererCompositor::RendererCompositor() {
|
||||
xr_enabled = GLOBAL_GET("rendering/xr/enabled");
|
||||
xr_enabled = GLOBAL_GET("xr/shaders/enabled");
|
||||
}
|
||||
|
||||
RendererCanvasRender *RendererCanvasRender::singleton = nullptr;
|
||||
|
|
|
@ -332,7 +332,7 @@ void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer
|
|||
RD::get_singleton()->draw_list_draw(draw_list, true);
|
||||
}
|
||||
|
||||
void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary) {
|
||||
void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview) {
|
||||
memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
|
||||
|
||||
if (p_flip_y) {
|
||||
|
@ -348,10 +348,18 @@ void EffectsRD::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer,
|
|||
copy_to_fb.push_constant.srgb = true;
|
||||
}
|
||||
|
||||
CopyToFBMode mode;
|
||||
if (p_multiview) {
|
||||
mode = p_secondary.is_valid() ? COPY_TO_FB_MULTIVIEW_WITH_DEPTH : COPY_TO_FB_MULTIVIEW;
|
||||
} else {
|
||||
mode = p_secondary.is_valid() ? COPY_TO_FB_COPY2 : COPY_TO_FB_COPY;
|
||||
}
|
||||
|
||||
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[p_secondary.is_valid() ? COPY_TO_FB_COPY2 : COPY_TO_FB_COPY].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
|
||||
if (p_secondary.is_valid()) {
|
||||
// TODO may need to do this differently when reading from depth buffer for multiview
|
||||
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_secondary), 1);
|
||||
}
|
||||
RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
|
||||
|
@ -2367,15 +2375,26 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
|
|||
copy_modes.push_back("\n");
|
||||
copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n");
|
||||
copy_modes.push_back("\n#define MODE_TWO_SOURCES\n");
|
||||
copy_modes.push_back("\n#define MULTIVIEW\n");
|
||||
copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n");
|
||||
|
||||
copy_to_fb.shader.initialize(copy_modes);
|
||||
|
||||
if (!RendererCompositorRD::singleton->is_xr_enabled()) {
|
||||
copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW, false);
|
||||
copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW_WITH_DEPTH, false);
|
||||
}
|
||||
|
||||
copy_to_fb.shader_version = copy_to_fb.shader.version_create();
|
||||
|
||||
//use additive
|
||||
|
||||
for (int i = 0; i < COPY_TO_FB_MAX; i++) {
|
||||
copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
if (copy_to_fb.shader.is_variant_enabled(i)) {
|
||||
copy_to_fb.pipelines[i].setup(copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
|
||||
} else {
|
||||
copy_to_fb.pipelines[i].clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -203,6 +203,9 @@ private:
|
|||
COPY_TO_FB_COPY,
|
||||
COPY_TO_FB_COPY_PANORAMA_TO_DP,
|
||||
COPY_TO_FB_COPY2,
|
||||
|
||||
COPY_TO_FB_MULTIVIEW,
|
||||
COPY_TO_FB_MULTIVIEW_WITH_DEPTH,
|
||||
COPY_TO_FB_MAX,
|
||||
|
||||
};
|
||||
|
@ -893,7 +896,7 @@ public:
|
|||
bool get_prefer_raster_effects();
|
||||
|
||||
void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness);
|
||||
void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID());
|
||||
void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false);
|
||||
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);
|
||||
void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
|
||||
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
|
||||
|
|
|
@ -4,7 +4,20 @@
|
|||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#ifdef MULTIVIEW
|
||||
#ifdef has_VK_KHR_multiview
|
||||
#extension GL_EXT_multiview : enable
|
||||
#define ViewIndex gl_ViewIndex
|
||||
#else // has_VK_KHR_multiview
|
||||
#define ViewIndex 0
|
||||
#endif // has_VK_KHR_multiview
|
||||
#endif //MULTIVIEW
|
||||
|
||||
#ifdef MULTIVIEW
|
||||
layout(location = 0) out vec3 uv_interp;
|
||||
#else
|
||||
layout(location = 0) out vec2 uv_interp;
|
||||
#endif
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec4 section;
|
||||
|
@ -19,9 +32,11 @@ params;
|
|||
|
||||
void main() {
|
||||
vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
|
||||
uv_interp = base_arr[gl_VertexIndex];
|
||||
|
||||
vec2 vpos = uv_interp;
|
||||
uv_interp.xy = base_arr[gl_VertexIndex];
|
||||
#ifdef MULTIVIEW
|
||||
uv_interp.z = ViewIndex;
|
||||
#endif
|
||||
vec2 vpos = uv_interp.xy;
|
||||
if (params.use_section) {
|
||||
vpos = params.section.xy + vpos * params.section.zw;
|
||||
}
|
||||
|
@ -39,6 +54,15 @@ void main() {
|
|||
|
||||
#VERSION_DEFINES
|
||||
|
||||
#ifdef MULTIVIEW
|
||||
#ifdef has_VK_KHR_multiview
|
||||
#extension GL_EXT_multiview : enable
|
||||
#define ViewIndex gl_ViewIndex
|
||||
#else // has_VK_KHR_multiview
|
||||
#define ViewIndex 0
|
||||
#endif // has_VK_KHR_multiview
|
||||
#endif //MULTIVIEW
|
||||
|
||||
layout(push_constant, std430) uniform Params {
|
||||
vec4 section;
|
||||
vec2 pixel_size;
|
||||
|
@ -52,12 +76,25 @@ layout(push_constant, std430) uniform Params {
|
|||
}
|
||||
params;
|
||||
|
||||
#ifdef MULTIVIEW
|
||||
layout(location = 0) in vec3 uv_interp;
|
||||
#else
|
||||
layout(location = 0) in vec2 uv_interp;
|
||||
#endif
|
||||
|
||||
#ifdef MULTIVIEW
|
||||
layout(set = 0, binding = 0) uniform sampler2DArray source_color;
|
||||
#ifdef MODE_TWO_SOURCES
|
||||
layout(set = 1, binding = 0) uniform sampler2DArray source_depth;
|
||||
layout(location = 1) out float depth;
|
||||
#endif /* MODE_TWO_SOURCES */
|
||||
#else
|
||||
layout(set = 0, binding = 0) uniform sampler2D source_color;
|
||||
#ifdef MODE_TWO_SOURCES
|
||||
layout(set = 1, binding = 0) uniform sampler2D source_color2;
|
||||
#endif
|
||||
#endif /* MODE_TWO_SOURCES */
|
||||
#endif /* MULTIVIEW */
|
||||
|
||||
layout(location = 0) out vec4 frag_color;
|
||||
|
||||
vec3 linear_to_srgb(vec3 color) {
|
||||
|
@ -68,9 +105,14 @@ vec3 linear_to_srgb(vec3 color) {
|
|||
}
|
||||
|
||||
void main() {
|
||||
#ifdef MULTIVIEW
|
||||
vec3 uv = uv_interp;
|
||||
#else
|
||||
vec2 uv = uv_interp;
|
||||
#endif
|
||||
|
||||
#ifdef MODE_PANORAMA_TO_DP
|
||||
// Note, multiview and panorama should not be mixed at this time
|
||||
|
||||
//obtain normal from dual paraboloid uv
|
||||
#define M_PI 3.14159265359
|
||||
|
@ -98,10 +140,20 @@ void main() {
|
|||
uv = 1.0 - uv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MULTIVIEW
|
||||
vec4 color = textureLod(source_color, uv, 0.0);
|
||||
#ifdef MODE_TWO_SOURCES
|
||||
// In multiview our 2nd input will be our depth map
|
||||
depth = textureLod(source_depth, uv, 0.0).r;
|
||||
#endif /* MODE_TWO_SOURCES */
|
||||
|
||||
#else
|
||||
vec4 color = textureLod(source_color, uv, 0.0);
|
||||
#ifdef MODE_TWO_SOURCES
|
||||
color += textureLod(source_color2, uv, 0.0);
|
||||
#endif
|
||||
#endif /* MODE_TWO_SOURCES */
|
||||
#endif /* MULTIVIEW */
|
||||
if (params.force_luminance) {
|
||||
color.rgb = vec3(max(max(color.r, color.g), color.b));
|
||||
}
|
||||
|
|
|
@ -548,7 +548,6 @@ void RendererViewport::draw_viewports() {
|
|||
|
||||
// get our xr interface in case we need it
|
||||
Ref<XRInterface> xr_interface;
|
||||
|
||||
XRServer *xr_server = XRServer::get_singleton();
|
||||
if (xr_server != nullptr) {
|
||||
// let our XR server know we're about to render our frames so we can get our frame timing
|
||||
|
|
|
@ -500,6 +500,7 @@ public:
|
|||
|
||||
virtual RID texture_create(const TextureFormat &p_format, const TextureView &p_view, const Vector<Vector<uint8_t>> &p_data = Vector<Vector<uint8_t>>()) = 0;
|
||||
virtual RID texture_create_shared(const TextureView &p_view, RID p_with_texture) = 0;
|
||||
virtual RID texture_create_from_extension(TextureType p_type, DataFormat p_format, TextureSamples p_samples, uint64_t p_flags, uint64_t p_image, uint64_t p_width, uint64_t p_height, uint64_t p_depth, uint64_t p_layers) = 0;
|
||||
|
||||
enum TextureSliceType {
|
||||
TEXTURE_SLICE_2D,
|
||||
|
|
|
@ -2999,7 +2999,7 @@ RenderingServer::RenderingServer() {
|
|||
GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512);
|
||||
ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"));
|
||||
|
||||
GLOBAL_DEF_RST("rendering/xr/enabled", false);
|
||||
GLOBAL_DEF_RST_BASIC("xr/shaders/enabled", false);
|
||||
|
||||
GLOBAL_DEF_RST("rendering/2d/options/use_software_skinning", true);
|
||||
GLOBAL_DEF_RST("rendering/2d/options/ninepatch_mode", 1);
|
||||
|
|
|
@ -65,10 +65,6 @@ void XRPositionalTracker::_bind_methods() {
|
|||
ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name")));
|
||||
ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
|
||||
ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "vector")));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_rumble"), &XRPositionalTracker::get_rumble);
|
||||
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRPositionalTracker::set_rumble);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble");
|
||||
};
|
||||
|
||||
void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) {
|
||||
|
@ -206,21 +202,8 @@ void XRPositionalTracker::set_input(const StringName &p_action_name, const Varia
|
|||
}
|
||||
}
|
||||
|
||||
real_t XRPositionalTracker::get_rumble() const {
|
||||
return rumble;
|
||||
};
|
||||
|
||||
void XRPositionalTracker::set_rumble(real_t p_rumble) {
|
||||
if (p_rumble > 0.0) {
|
||||
rumble = p_rumble;
|
||||
} else {
|
||||
rumble = 0.0;
|
||||
};
|
||||
};
|
||||
|
||||
XRPositionalTracker::XRPositionalTracker() {
|
||||
type = XRServer::TRACKER_UNKNOWN;
|
||||
name = "Unknown";
|
||||
hand = TRACKER_HAND_UNKNOWN;
|
||||
rumble = 0.0;
|
||||
};
|
||||
|
|
|
@ -62,10 +62,6 @@ private:
|
|||
Map<StringName, Ref<XRPose>> poses;
|
||||
Map<StringName, Variant> inputs;
|
||||
|
||||
int joy_id; // if we also have a related joystick entity, the id of the joystick
|
||||
Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker
|
||||
real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, xr_interface is responsible for execution
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
|
@ -87,10 +83,6 @@ public:
|
|||
Variant get_input(const StringName &p_action_name) const;
|
||||
void set_input(const StringName &p_action_name, const Variant &p_value);
|
||||
|
||||
// TODO replace by new implementation
|
||||
real_t get_rumble() const;
|
||||
void set_rumble(real_t p_rumble);
|
||||
|
||||
XRPositionalTracker();
|
||||
~XRPositionalTracker() {}
|
||||
};
|
||||
|
|
|
@ -348,9 +348,10 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker
|
|||
}
|
||||
|
||||
void XRServer::_process() {
|
||||
/* called from renderer_viewport.draw_viewports right before we start drawing our viewports */
|
||||
// called from our main game loop before we handle physics and game logic
|
||||
// note that we can have multiple interfaces active if we have interfaces that purely handle tracking
|
||||
|
||||
/* process all active interfaces */
|
||||
// process all active interfaces
|
||||
for (int i = 0; i < interfaces.size(); i++) {
|
||||
if (!interfaces[i].is_valid()) {
|
||||
// ignore, not a valid reference
|
||||
|
|
Loading…
Reference in a new issue