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;