diff --git a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml index 130f8d6599a..8921f8edcda 100644 --- a/modules/openxr/doc_classes/OpenXRCompositionLayer.xml +++ b/modules/openxr/doc_classes/OpenXRCompositionLayer.xml @@ -49,6 +49,10 @@ The [SubViewport] to render on the composition layer. + + If enabled, the OpenXR swapchain will be created with the [code]XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT[/code] flag, which will protect its contents from CPU access. + When used with an Android Surface, this may allow DRM content to be presented, and will only take effect when the Surface is first created; later changes to this property will have no effect. + The sort order for this composition layer. Higher numbers will be shown in front of lower numbers. [b]Note:[/b] This will have no effect if a fallback mesh is being used. diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.cpp b/modules/openxr/extensions/openxr_composition_layer_extension.cpp index 56badf59189..ded3c6175ea 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.cpp +++ b/modules/openxr/extensions/openxr_composition_layer_extension.cpp @@ -269,12 +269,19 @@ void OpenXRViewportCompositionLayerProvider::create_android_surface() { } } + // Check to see if content should be protected. + XrSwapchainCreateFlags create_flags = 0; + + if (protected_content) { + create_flags = XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT; + } + // The XR_FB_android_surface_swapchain_create extension mandates that format, sampleCount, // faceCount, arraySize, and mipCount must be zero. XrSwapchainCreateInfo info = { XR_TYPE_SWAPCHAIN_CREATE_INFO, // type next_pointer, // next - 0, // createFlags + create_flags, // createFlags XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, // usageFlags 0, // format 0, // sampleCount @@ -471,7 +478,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p // See if our current swapchain is outdated. if (subviewport.swapchain_info.get_swapchain() != XR_NULL_HANDLE) { // If this swap chain, or the previous one, were static, then we can't reuse it. - if (swapchain_size == subviewport.viewport_size && !p_static_image && !subviewport.static_image) { + if (swapchain_size == subviewport.viewport_size && !p_static_image && !subviewport.static_image && protected_content == subviewport.swapchain_protected_content) { // We're all good! Just acquire it. // We can ignore should_render here, return will be false. bool should_render = true; @@ -489,6 +496,9 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p if (p_static_image) { create_flags |= XR_SWAPCHAIN_CREATE_STATIC_IMAGE_BIT; } + if (protected_content) { + create_flags |= XR_SWAPCHAIN_CREATE_PROTECTED_CONTENT_BIT; + } if (!subviewport.swapchain_info.create(create_flags, XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT, swapchain_format, subviewport.viewport_size.width, subviewport.viewport_size.height, sample_count, array_size)) { swapchain_size = Size2i(); return false; @@ -503,6 +513,7 @@ bool OpenXRViewportCompositionLayerProvider::update_and_acquire_swapchain(bool p swapchain_size = subviewport.viewport_size; subviewport.static_image = p_static_image; + subviewport.swapchain_protected_content = protected_content; return ret; } diff --git a/modules/openxr/extensions/openxr_composition_layer_extension.h b/modules/openxr/extensions/openxr_composition_layer_extension.h index 5ad3d231bab..3515c8efbc9 100644 --- a/modules/openxr/extensions/openxr_composition_layer_extension.h +++ b/modules/openxr/extensions/openxr_composition_layer_extension.h @@ -161,6 +161,7 @@ private: Size2i viewport_size; OpenXRAPI::OpenXRSwapChainInfo swapchain_info; bool static_image = false; + bool swapchain_protected_content = false; } subviewport; #ifdef ANDROID_ENABLED @@ -171,6 +172,7 @@ private: #endif bool use_android_surface = false; + bool protected_content = false; Size2i swapchain_size; OpenXRAPI *openxr_api = nullptr; @@ -204,6 +206,9 @@ public: void set_use_android_surface(bool p_enable, Size2i p_size); bool get_use_android_surface() const { return use_android_surface; } + void set_protected_content(bool p_protected_content) { protected_content = p_protected_content; } + bool is_protected_content() const { return protected_content; } + Ref get_android_surface(); void set_extension_property_values(const Dictionary &p_property_values); diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp index 61f5cff4fd6..a9a119bc979 100644 --- a/modules/openxr/scene/openxr_composition_layer.cpp +++ b/modules/openxr/scene/openxr_composition_layer.cpp @@ -113,6 +113,9 @@ void OpenXRCompositionLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_android_surface"), &OpenXRCompositionLayer::get_android_surface); ClassDB::bind_method(D_METHOD("is_natively_supported"), &OpenXRCompositionLayer::is_natively_supported); + ClassDB::bind_method(D_METHOD("is_protected_content"), &OpenXRCompositionLayer::is_protected_content); + ClassDB::bind_method(D_METHOD("set_protected_content", "protected_content"), &OpenXRCompositionLayer::set_protected_content); + ClassDB::bind_method(D_METHOD("set_min_filter", "mode"), &OpenXRCompositionLayer::set_min_filter); ClassDB::bind_method(D_METHOD("get_min_filter"), &OpenXRCompositionLayer::get_min_filter); @@ -150,6 +153,7 @@ void OpenXRCompositionLayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "layer_viewport", PROPERTY_HINT_NODE_TYPE, "SubViewport"), "set_layer_viewport", "get_layer_viewport"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_android_surface", PROPERTY_HINT_NONE, ""), "set_use_android_surface", "get_use_android_surface"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "protected_content", PROPERTY_HINT_NONE, ""), "set_protected_content", "is_protected_content"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "android_surface_size", PROPERTY_HINT_NONE, ""), "set_android_surface_size", "get_android_surface_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sort_order", PROPERTY_HINT_NONE, ""), "set_sort_order", "get_sort_order"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "alpha_blend", PROPERTY_HINT_NONE, ""), "set_alpha_blend", "get_alpha_blend"); @@ -419,6 +423,14 @@ bool OpenXRCompositionLayer::is_natively_supported() const { return false; } +void OpenXRCompositionLayer::set_protected_content(bool p_protected_content) { + openxr_layer_provider->set_protected_content(p_protected_content); +} + +bool OpenXRCompositionLayer::is_protected_content() const { + return openxr_layer_provider->is_protected_content(); +} + void OpenXRCompositionLayer::set_min_filter(Filter p_mode) { if (swapchain_state->min_filter == (OpenXRViewportCompositionLayerProvider::Filter)p_mode) { return; diff --git a/modules/openxr/scene/openxr_composition_layer.h b/modules/openxr/scene/openxr_composition_layer.h index ae9da59c37b..f2037bf0866 100644 --- a/modules/openxr/scene/openxr_composition_layer.h +++ b/modules/openxr/scene/openxr_composition_layer.h @@ -155,6 +155,9 @@ public: Ref get_android_surface(); bool is_natively_supported() const; + void set_protected_content(bool p_protected_content); + bool is_protected_content() const; + void set_min_filter(Filter p_mode); Filter get_min_filter() const;