Merge pull request #108644 from bnjmntmm/secure-android-surface

Use of `XrSwapchainCreateFlags` for `OpenXRCompositionLayer`
This commit is contained in:
Thaddeus Crews 2025-10-06 09:06:45 -05:00
commit 788745e5b8
No known key found for this signature in database
GPG key ID: 8C6E5FEB5FC03CCC
5 changed files with 37 additions and 2 deletions

View file

@ -49,6 +49,10 @@
<member name="layer_viewport" type="SubViewport" setter="set_layer_viewport" getter="get_layer_viewport">
The [SubViewport] to render on the composition layer.
</member>
<member name="protected_content" type="bool" setter="set_protected_content" getter="is_protected_content" default="false">
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.
</member>
<member name="sort_order" type="int" setter="set_sort_order" getter="get_sort_order" default="1">
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.

View file

@ -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;
}

View file

@ -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<JavaObject> get_android_surface();
void set_extension_property_values(const Dictionary &p_property_values);

View file

@ -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;

View file

@ -155,6 +155,9 @@ public:
Ref<JavaObject> 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;