This commit is contained in:
Bastiaan Olij 2021-11-11 08:16:19 +00:00 committed by GitHub
commit 7e439b75ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 869 additions and 186 deletions

View file

@ -547,6 +547,21 @@
<description>
</description>
</method>
<method name="texture_create_from_extension">
<return type="RID" />
<argument index="0" name="type" type="int" enum="RenderingDevice.TextureType" />
<argument index="1" name="format" type="int" enum="RenderingDevice.DataFormat" />
<argument index="2" name="samples" type="int" enum="RenderingDevice.TextureSamples" />
<argument index="3" name="flags" type="int" />
<argument index="4" name="image" type="int" />
<argument index="5" name="width" type="int" />
<argument index="6" name="height" type="int" />
<argument index="7" name="depth" type="int" />
<argument index="8" name="layers" type="int" />
<description>
Create a texture object based an image handle already created within an GDNative extension.
</description>
</method>
<method name="texture_create_shared">
<return type="RID" />
<argument index="0" name="view" type="RDTextureView" />

View file

@ -36,6 +36,16 @@
<description>
</description>
</method>
<method name="_get_external_color_texture" qualifiers="virtual">
<return type="RID" />
<description>
</description>
</method>
<method name="_get_external_depth_texture" qualifiers="virtual">
<return type="RID" />
<description>
</description>
</method>
<method name="_get_name" qualifiers="virtual const">
<return type="StringName" />
<description>

View file

@ -3622,6 +3622,12 @@ RID RasterizerStorageGLES3::render_target_create() {
return render_target_owner.make_rid(rt);
}
void RasterizerStorageGLES3::render_target_update(RID p_render_target) {
// TODO need to look into if this applies here and how to implement it.
// The idea here is not to create the textures and framebuffer until we need it for the first time.
// Especially when XR is used we may end up creating things multiple times and then not using it.
}
void RasterizerStorageGLES3::render_target_set_position(RID p_render_target, int p_x, int p_y) {
#ifdef OPENGL_DISABLE_RENDER_TARGETS
return;
@ -3671,113 +3677,14 @@ RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) {
}
}
void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
void RasterizerStorageGLES3::render_target_set_external_textures(RID p_render_target, RID p_color, RID p_depth) {
#ifdef OPENGL_DISABLE_RENDER_TARGETS
return;
#endif
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
// TODO re-implement this once stereo support has been added
if (p_texture_id == 0) {
if (rt->external.fbo != 0) {
// free this
glDeleteFramebuffers(1, &rt->external.fbo);
// and this
if (rt->external.depth != 0) {
glDeleteRenderbuffers(1, &rt->external.depth);
}
// clean up our texture
Texture *t = texture_owner.get_or_null(rt->external.texture);
t->alloc_height = 0;
t->alloc_width = 0;
t->width = 0;
t->height = 0;
t->active = false;
texture_owner.free(rt->external.texture);
memdelete(t);
rt->external.fbo = 0;
rt->external.color = 0;
rt->external.depth = 0;
}
} else {
Texture *t;
if (rt->external.fbo == 0) {
// create our fbo
glGenFramebuffers(1, &rt->external.fbo);
bind_framebuffer(rt->external.fbo);
// allocate a texture
t = memnew(Texture);
t->type = RenderingDevice::TEXTURE_TYPE_2D;
t->flags = 0;
t->width = 0;
t->height = 0;
t->alloc_height = 0;
t->alloc_width = 0;
t->format = Image::FORMAT_RGBA8;
t->target = GL_TEXTURE_2D;
t->gl_format_cache = 0;
t->gl_internal_format_cache = 0;
t->gl_type_cache = 0;
t->data_size = 0;
t->compressed = false;
t->srgb = false;
t->total_data_size = 0;
t->ignore_mipmaps = false;
t->mipmaps = 1;
t->active = true;
t->tex_id = 0;
t->render_target = rt;
rt->external.texture = texture_owner.make_rid(t);
} else {
// bind our frame buffer
bind_framebuffer(rt->external.fbo);
// find our texture
t = texture_owner.get_or_null(rt->external.texture);
}
// set our texture
t->tex_id = p_texture_id;
rt->external.color = p_texture_id;
// size shouldn't be different
t->width = rt->width;
t->height = rt->height;
t->alloc_height = rt->width;
t->alloc_width = rt->height;
// Switch our texture on our frame buffer
{
// set our texture as the destination for our framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0);
// seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :)
if (config.support_depth_texture) {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0);
} else {
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
}
}
// check status and unbind
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
bind_framebuffer_system();
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("framebuffer fail, status: %x\n", status);
}
ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE);
}
return;
}
void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {

View file

@ -1256,10 +1256,11 @@ public:
void _set_current_render_target(RID p_render_target);
RID render_target_create() override;
void render_target_update(RID p_render_target) override;
void render_target_set_position(RID p_render_target, int p_x, int p_y) override;
void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override;
RID render_target_get_texture(RID p_render_target) override;
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override;
void render_target_set_external_textures(RID p_render_target, RID p_color, RID p_depth) override;
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override;
bool render_target_was_used(RID p_render_target) override;

View file

@ -2170,6 +2170,125 @@ 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.
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;
// Do we need to do something with texture.allowed_shared_formats?
// 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, mayb 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, TextureSliceType p_slice_type) {
_THREAD_SAFE_METHOD_
@ -8714,7 +8833,7 @@ void RenderingDeviceVulkan::_free_pending_resources(int p_frame) {
WARN_PRINT("Deleted a texture while it was bound..");
}
vkDestroyImageView(device, texture->view, nullptr);
if (texture->owner.is_null()) {
if (texture->owner.is_null() && texture->allocation != nullptr) {
//actually owns the image and the allocation too
image_memory -= texture->allocation_info.size;
vmaDestroyImage(allocator, texture->image, texture->allocation);

View file

@ -1036,6 +1036,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, 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);

View file

@ -339,6 +339,25 @@ Error VulkanContext::_initialize_extensions() {
if (!strcmp(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, instance_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
}
// TODO Need to switch these, they are needed for OpenXR
if (!strcmp(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, instance_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
}
if (!strcmp(VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, instance_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
}
#ifdef WINDOWS_ENABLED
if (!strcmp(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, instance_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
}
#endif
// END TODO
if (enabled_extension_count >= MAX_EXTENSIONS) {
free(instance_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
@ -784,6 +803,33 @@ Error VulkanContext::_create_physical_device() {
// if multiview is supported, enable it
extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME;
}
// TODO Need to switch these, tehy are needed for OpenXR (or do we just enable them anyway?)
if (!strcmp(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME;
}
if (!strcmp(VK_EXT_DEBUG_MARKER_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_EXT_DEBUG_MARKER_EXTENSION_NAME;
}
#ifdef WINDOWS_ENABLED
if (!strcmp(VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, device_extensions[i].extensionName)) {
extension_names[enabled_extension_count++] = VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME;
}
#endif
// END TODO
if (enabled_extension_count >= MAX_EXTENSIONS) {
free(device_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");

View file

@ -0,0 +1,438 @@
/*************************************************************************/
/* xr_interface_gdnative.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 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 "xr_interface_gdnative.h"
#include "core/input/input.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/xr/xr_positional_tracker.h"
void XRInterfaceGDNative::_bind_methods() {
ADD_PROPERTY_DEFAULT("interface_is_initialized", false);
ADD_PROPERTY_DEFAULT("ar_is_anchor_detection_enabled", false);
}
XRInterfaceGDNative::XRInterfaceGDNative() {
print_verbose("Construct gdnative interface\n");
// we won't have our data pointer until our library gets set
data = nullptr;
interface = nullptr;
}
XRInterfaceGDNative::~XRInterfaceGDNative() {
print_verbose("Destruct gdnative interface\n");
if (interface != nullptr && is_initialized()) {
uninitialize();
};
// cleanup after ourselves
cleanup();
}
void XRInterfaceGDNative::cleanup() {
if (interface != nullptr) {
interface->destructor(data);
data = nullptr;
interface = nullptr;
}
}
void XRInterfaceGDNative::set_interface(const godot_xr_interface_gdnative *p_interface) {
// this should only be called once, just being paranoid..
if (interface) {
cleanup();
interface = NULL;
}
// validate
ERR_FAIL_NULL(p_interface);
ERR_FAIL_COND_MSG(p_interface->version.major < 4, "This is an incompatible GDNative XR plugin.");
// bind to our interface
interface = p_interface;
// Now we do our constructing...
data = interface->constructor((godot_object *)this);
}
StringName XRInterfaceGDNative::get_name() const {
ERR_FAIL_COND_V(interface == nullptr, StringName());
godot_string result = interface->get_name(data);
StringName name = *(String *)&result;
godot_string_destroy(&result);
return name;
}
int XRInterfaceGDNative::get_capabilities() const {
int capabilities;
ERR_FAIL_COND_V(interface == nullptr, 0); // 0 = None
capabilities = interface->get_capabilities(data);
return capabilities;
}
bool XRInterfaceGDNative::get_anchor_detection_is_enabled() const {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->get_anchor_detection_is_enabled(data);
}
void XRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
ERR_FAIL_COND(interface == nullptr);
interface->set_anchor_detection_is_enabled(data, p_enable);
}
int XRInterfaceGDNative::get_camera_feed_id() {
ERR_FAIL_COND_V(interface == nullptr, 0);
return (unsigned int)interface->get_camera_feed_id(data);
}
uint32_t XRInterfaceGDNative::get_view_count() {
uint32_t view_count;
ERR_FAIL_COND_V(interface == nullptr, 1);
view_count = interface->get_view_count(data);
return view_count;
}
bool XRInterfaceGDNative::is_initialized() const {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->is_initialized(data);
}
bool XRInterfaceGDNative::initialize() {
ERR_FAIL_COND_V(interface == nullptr, false);
bool initialized = interface->initialize(data);
if (initialized) {
// if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
XRServer *xr_server = XRServer::get_singleton();
if ((xr_server != nullptr) && (xr_server->get_primary_interface() == nullptr)) {
xr_server->set_primary_interface(this);
};
};
return initialized;
}
void XRInterfaceGDNative::uninitialize() {
ERR_FAIL_COND(interface == nullptr);
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
// Whatever happens, make sure this is no longer our primary interface
xr_server->clear_primary_interface_if(this);
}
interface->uninitialize(data);
}
Size2 XRInterfaceGDNative::get_render_targetsize() {
ERR_FAIL_COND_V(interface == nullptr, Size2());
godot_vector2 result = interface->get_render_targetsize(data);
Vector2 *vec = (Vector2 *)&result;
return *vec;
}
Transform3D XRInterfaceGDNative::get_camera_transform() {
Transform3D *ret;
ERR_FAIL_COND_V(interface == nullptr, Transform3D());
godot_transform3d t = interface->get_camera_transform(data);
ret = (Transform3D *)&t;
return *ret;
}
Transform3D XRInterfaceGDNative::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
Transform3D *ret;
ERR_FAIL_COND_V(interface == nullptr, Transform3D());
godot_transform3d t = interface->get_transform_for_view(data, (int)p_view, (godot_transform3d *)&p_cam_transform);
ret = (Transform3D *)&t;
return *ret;
}
CameraMatrix XRInterfaceGDNative::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
CameraMatrix cm;
ERR_FAIL_COND_V(interface == nullptr, CameraMatrix());
interface->fill_projection_for_view(data, (godot_real_t *)cm.matrix, (godot_int)p_view, p_aspect, p_z_near, p_z_far);
return cm;
}
Vector<BlitToScreen> XRInterfaceGDNative::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
// possibly move this as a member variable and add a callback to populate?
Vector<BlitToScreen> blit_to_screen;
ERR_FAIL_COND_V(interface == nullptr, blit_to_screen);
// must implement
interface->commit_views(data, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
return blit_to_screen;
}
void XRInterfaceGDNative::process() {
ERR_FAIL_COND(interface == nullptr);
interface->process(data);
}
void XRInterfaceGDNative::notification(int p_what) {
ERR_FAIL_COND(interface == nullptr);
interface->notification(data, p_what);
}
/////////////////////////////////////////////////////////////////////////////////////
// some helper callbacks
extern "C" {
void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface) {
// Must be on a version 4 plugin
ERR_FAIL_COND_MSG(p_interface->version.major < 4, "GDNative XR interfaces build for Godot 3.x are not supported.");
Ref<XRInterfaceGDNative> new_interface;
new_interface.instantiate();
new_interface->set_interface((const godot_xr_interface_gdnative *)p_interface);
XRServer::get_singleton()->add_interface(new_interface);
}
godot_real_t GDAPI godot_xr_get_worldscale() {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 1.0);
return xr_server->get_world_scale();
}
godot_transform3d GDAPI godot_xr_get_reference_frame() {
godot_transform3d reference_frame;
Transform3D *reference_frame_ptr = (Transform3D *)&reference_frame;
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
*reference_frame_ptr = xr_server->get_reference_frame();
} else {
memnew_placement(&reference_frame, Transform3D);
}
return reference_frame;
}
void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) {
// blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD
XRInterface::Eyes eye = (XRInterface::Eyes)p_eye;
#if 0
RID *render_target = (RID *)p_render_target;
#endif
Rect2 screen_rect = *(Rect2 *)p_rect;
if (eye == XRInterface::EYE_LEFT) {
screen_rect.size.x /= 2.0;
} else if (p_eye == XRInterface::EYE_RIGHT) {
screen_rect.size.x /= 2.0;
screen_rect.position.x += screen_rect.size.x;
}
#ifndef _MSC_VER
#warning this needs to be redone
#endif
#if 0
RSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0);
#endif
}
godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target) {
// In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID
// This is a handy function to expose that.
#if 0
RID *render_target = (RID *)p_render_target;
RID eye_texture = RSG::storage->render_target_get_texture(*render_target);
#endif
#ifndef _MSC_VER
#warning need to obtain this ID again
#endif
uint32_t texid = 0; //RS::get_singleton()->texture_get_texid(eye_texture);
return texid;
}
godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0);
Input *input = Input::get_singleton();
ERR_FAIL_NULL_V(input, 0);
Ref<XRPositionalTracker> new_tracker;
new_tracker.instantiate();
new_tracker->set_tracker_name(p_device_name);
new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
if (p_hand == 1) {
new_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
} else if (p_hand == 2) {
new_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
}
// also register as joystick...
int joyid = input->get_unused_joy_id();
if (joyid != -1) {
new_tracker->set_joy_id(joyid);
input->joy_connection_changed(joyid, true, p_device_name, "");
}
if (p_tracks_orientation) {
Basis orientation;
new_tracker->set_orientation(orientation);
}
if (p_tracks_position) {
Vector3 position;
new_tracker->set_position(position);
}
// add our tracker to our server and remember its pointer
xr_server->add_tracker(new_tracker);
// note, this ID is only unique within controllers!
return new_tracker->get_tracker_id();
}
void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
Ref<XRPositionalTracker> remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (remove_tracker.is_valid()) {
// unset our joystick if applicable
int joyid = remove_tracker->get_joy_id();
if (joyid != -1) {
input->joy_connection_changed(joyid, false, "", "");
remove_tracker->set_joy_id(-1);
}
// remove our tracker from our server
xr_server->remove_tracker(remove_tracker);
remove_tracker.unref();
}
}
void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
Transform3D *transform = (Transform3D *)p_transform;
if (p_tracks_orientation) {
tracker->set_orientation(transform->basis);
}
if (p_tracks_position) {
tracker->set_rw_position(transform->origin);
}
}
}
void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
input->joy_button(joyid, (JoyButton)p_button, p_is_pressed);
}
}
}
void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
Input::JoyAxisValue jx;
jx.min = p_can_be_negative ? -1 : 0;
jx.value = p_value;
input->joy_axis(joyid, (JoyAxis)p_axis, jx);
}
}
}
godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
return tracker->get_rumble();
}
return 0.0;
}
}

View file

@ -659,10 +659,11 @@ public:
/* RENDER TARGET */
RID render_target_create() override { return RID(); }
void render_target_update(RID p_render_target) override {}
void render_target_set_position(RID p_render_target, int p_x, int p_y) override {}
void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override {}
RID render_target_get_texture(RID p_render_target) override { return RID(); }
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override {}
void render_target_set_external_textures(RID p_render_target, RID p_color, RID p_depth) override {}
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override {}
bool render_target_was_used(RID p_render_target) override { return false; }
void render_target_set_as_unused(RID p_render_target) override {}

View file

@ -7467,6 +7467,20 @@ AABB RendererStorageRD::lightmap_get_aabb(RID p_lightmap) const {
/* RENDER TARGET API */
void RendererStorageRD::_mark_render_target_dirty(RenderTarget *rt) {
if (rt->texture.is_null()) {
//create a placeholder until updated
rt->texture = texture_allocate();
texture_2d_placeholder_initialize(rt->texture);
Texture *tex = texture_owner.get_or_null(rt->texture);
tex->is_render_target = true;
}
_clear_render_target(rt);
rt->is_dirty = true;
}
void RendererStorageRD::_clear_render_target(RenderTarget *rt) {
//free in reverse dependency order
if (rt->framebuffer.is_valid()) {
@ -7509,81 +7523,137 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) {
if (rt->size.width == 0 || rt->size.height == 0) {
return;
}
//until we implement support for HDR monitors (and render target is attached to screen), this is enough.
rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
RD::TextureFormat rd_format;
RD::TextureView rd_view;
{ //attempt register
rd_format.format = rt->color_format;
rd_format.width = rt->size.width;
rd_format.height = rt->size.height;
rd_format.depth = 1;
rd_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview
rd_format.mipmaps = 1;
if (rd_format.array_layers > 1) { // why are we not using rt->texture_type ??
rd_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
} else {
rd_format.texture_type = RD::TEXTURE_TYPE_2D;
}
rd_format.samples = RD::TEXTURE_SAMPLES_1;
rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
rd_format.shareable_formats.push_back(rt->color_format);
rd_format.shareable_formats.push_back(rt->color_format_srgb);
}
if (rt->external_color.is_null()) {
//until we implement support for HDR monitors (and render target is attached to screen), this is enough.
rt->color_format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
rt->color_format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB;
rt->image_format = rt->flags[RENDER_TARGET_TRANSPARENT] ? Image::FORMAT_RGBA8 : Image::FORMAT_RGB8;
rt->color = RD::get_singleton()->texture_create(rd_format, rd_view);
ERR_FAIL_COND(rt->color.is_null());
Vector<RID> fb_textures;
fb_textures.push_back(rt->color);
rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
if (rt->framebuffer.is_null()) {
_clear_render_target(rt);
ERR_FAIL_COND(rt->framebuffer.is_null());
}
{ //update texture
Texture *tex = texture_owner.get_or_null(rt->texture);
//free existing textures
if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
RD::get_singleton()->free(tex->rd_texture);
}
if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
RD::get_singleton()->free(tex->rd_texture_srgb);
RD::TextureFormat rd_format;
RD::TextureView rd_view;
{ //attempt register
rd_format.format = rt->color_format;
rd_format.width = rt->size.width;
rd_format.height = rt->size.height;
rd_format.depth = 1;
rd_format.array_layers = rt->view_count; // for stereo we create two (or more) layers, need to see if we can make fallback work like this too if we don't have multiview
rd_format.mipmaps = 1;
if (rd_format.array_layers > 1) { // why are we not using rt->texture_type ??
rd_format.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
} else {
rd_format.texture_type = RD::TEXTURE_TYPE_2D;
}
rd_format.samples = RD::TEXTURE_SAMPLES_1;
rd_format.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
rd_format.shareable_formats.push_back(rt->color_format);
rd_format.shareable_formats.push_back(rt->color_format_srgb);
}
tex->rd_texture = RID();
tex->rd_texture_srgb = RID();
rt->color = RD::get_singleton()->texture_create(rd_format, rd_view);
ERR_FAIL_COND(rt->color.is_null());
//create shared textures to the color buffer,
//so transparent can be supported
RD::TextureView view;
view.format_override = rt->color_format;
if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
Vector<RID> fb_textures;
fb_textures.push_back(rt->color);
rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
if (rt->framebuffer.is_null()) {
_clear_render_target(rt);
ERR_FAIL_COND(rt->framebuffer.is_null());
}
tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color);
if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
view.format_override = rt->color_format_srgb;
tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color);
}
tex->rd_view = view;
tex->width = rt->size.width;
tex->height = rt->size.height;
tex->width_2d = rt->size.width;
tex->height_2d = rt->size.height;
tex->rd_format = rt->color_format;
tex->rd_format_srgb = rt->color_format_srgb;
tex->format = rt->image_format;
Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
for (int i = 0; i < proxies.size(); i++) {
texture_proxy_update(proxies[i], rt->texture);
{ //update texture
Texture *tex = texture_owner.get_or_null(rt->texture);
//free existing textures
if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
RD::get_singleton()->free(tex->rd_texture);
}
if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
RD::get_singleton()->free(tex->rd_texture_srgb);
}
tex->rd_texture = RID();
tex->rd_texture_srgb = RID();
//create shared textures to the color buffer,
//so transparent can be supported
RD::TextureView view;
view.format_override = rt->color_format;
if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
}
tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->color);
if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
view.format_override = rt->color_format_srgb;
tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->color);
}
tex->rd_view = view;
tex->width = rt->size.width;
tex->height = rt->size.height;
tex->width_2d = rt->size.width;
tex->height_2d = rt->size.height;
tex->rd_format = rt->color_format;
tex->rd_format_srgb = rt->color_format_srgb;
tex->format = rt->image_format;
Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
for (int i = 0; i < proxies.size(); i++) {
texture_proxy_update(proxies[i], rt->texture);
}
}
} else {
// use our external texture
Vector<RID> fb_textures;
fb_textures.push_back(rt->external_color);
rt->framebuffer = RD::get_singleton()->framebuffer_create(fb_textures, RenderingDevice::INVALID_ID, rt->view_count);
if (rt->framebuffer.is_null()) {
_clear_render_target(rt);
ERR_FAIL_COND(rt->framebuffer.is_null());
}
{ //update texture
// TODO change this to get color info from our external texture instead...
Texture *tex = texture_owner.get_or_null(rt->texture);
//free existing textures
if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) {
RD::get_singleton()->free(tex->rd_texture);
}
if (RD::get_singleton()->texture_is_valid(tex->rd_texture_srgb)) {
RD::get_singleton()->free(tex->rd_texture_srgb);
}
tex->rd_texture = RID();
tex->rd_texture_srgb = RID();
//create shared textures to the color buffer,
//so transparent can be supported
RD::TextureView view;
view.format_override = rt->color_format;
if (!rt->flags[RENDER_TARGET_TRANSPARENT]) {
view.swizzle_a = RD::TEXTURE_SWIZZLE_ONE;
}
tex->rd_texture = RD::get_singleton()->texture_create_shared(view, rt->external_color);
if (rt->color_format_srgb != RD::DATA_FORMAT_MAX) {
view.format_override = rt->color_format_srgb;
tex->rd_texture_srgb = RD::get_singleton()->texture_create_shared(view, rt->external_color);
}
tex->rd_view = view;
tex->width = rt->size.width;
tex->height = rt->size.height;
tex->width_2d = rt->size.width;
tex->height_2d = rt->size.height;
tex->rd_format = rt->color_format;
tex->rd_format_srgb = rt->color_format_srgb;
tex->format = rt->image_format;
Vector<RID> proxies = tex->proxies; //make a copy, since update may change it
for (int i = 0; i < proxies.size(); i++) {
texture_proxy_update(proxies[i], rt->texture);
}
}
}
}
@ -7645,10 +7715,20 @@ RID RendererStorageRD::render_target_create() {
for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) {
render_target.flags[i] = false;
}
_update_render_target(&render_target);
_mark_render_target_dirty(&render_target);
return render_target_owner.make_rid(render_target);
}
void RendererStorageRD::render_target_update(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (rt->is_dirty) {
_update_render_target(rt);
rt->is_dirty = false;
}
}
void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x, int p_y) {
//unused for this render target
}
@ -7660,7 +7740,7 @@ void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width,
rt->size.x = p_width;
rt->size.y = p_height;
rt->view_count = p_view_count;
_update_render_target(rt);
_mark_render_target_dirty(rt);
}
}
@ -7671,14 +7751,22 @@ RID RendererStorageRD::render_target_get_texture(RID p_render_target) {
return rt->texture;
}
void RendererStorageRD::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {
void RendererStorageRD::render_target_set_external_textures(RID p_render_target, RID p_color, RID p_depth) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
if (rt->external_color != p_color || rt->external_depth != p_depth) {
rt->external_color = p_color;
rt->external_depth = p_depth;
_mark_render_target_dirty(rt);
}
}
void RendererStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
ERR_FAIL_COND(!rt);
rt->flags[p_flag] = p_value;
_update_render_target(rt);
_mark_render_target_dirty(rt);
}
bool RendererStorageRD::render_target_was_used(RID p_render_target) {

View file

@ -1152,6 +1152,7 @@ private:
/* RENDER TARGET */
struct RenderTarget {
bool is_dirty = true;
Size2i size;
uint32_t view_count;
RID framebuffer;
@ -1170,6 +1171,9 @@ private:
RID backbuffer_fb;
RID backbuffer_mipmap0;
RID external_color; // used for XR
RID external_depth;
struct BackbufferMipmap {
RID mipmap;
RID mipmap_copy;
@ -1200,6 +1204,7 @@ private:
mutable RID_Owner<RenderTarget> render_target_owner;
void _mark_render_target_dirty(RenderTarget *rt);
void _clear_render_target(RenderTarget *rt);
void _update_render_target(RenderTarget *rt);
void _create_render_target_backbuffer(RenderTarget *rt);
@ -2326,10 +2331,11 @@ public:
/* RENDER TARGET API */
RID render_target_create();
void render_target_update(RID p_render_target);
void render_target_set_position(RID p_render_target, int p_x, int p_y);
void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count);
RID render_target_get_texture(RID p_render_target);
void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id);
void render_target_set_external_textures(RID p_render_target, RID p_color, RID p_depth);
void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value);
bool render_target_was_used(RID p_render_target);
void render_target_set_as_unused(RID p_render_target);

View file

@ -588,10 +588,11 @@ public:
};
virtual RID render_target_create() = 0;
virtual void render_target_update(RID p_render_target) = 0;
virtual void render_target_set_position(RID p_render_target, int p_x, int p_y) = 0;
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) = 0;
virtual RID render_target_get_texture(RID p_render_target) = 0;
virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
virtual void render_target_set_external_textures(RID p_render_target, RID p_color, RID p_depth) = 0;
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
virtual bool render_target_was_used(RID p_render_target) = 0;
virtual void render_target_set_as_unused(RID p_render_target) = 0;

View file

@ -573,9 +573,11 @@ void RendererViewport::draw_viewports() {
uint32_t view_count = xr_interface->get_view_count();
RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);
// check for an external texture destination (disabled for now, not yet supported)
// RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
RSG::storage->render_target_set_external_texture(vp->render_target, 0);
// check for an external texture destination
RSG::storage->render_target_set_external_textures(vp->render_target, xr_interface->get_external_color_texture(), xr_interface->get_external_depth_texture());
// (Re)create our RT if needed
RSG::storage->render_target_update(vp->render_target);
// render...
RSG::scene->set_debug_draw_mode(vp->debug_draw);
@ -583,8 +585,6 @@ void RendererViewport::draw_viewports() {
// and draw viewport
_draw_viewport(vp);
// measure
// commit our eyes
Vector<BlitToScreen> blits = xr_interface->commit_views(vp->render_target, vp->viewport_to_screen_rect);
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) {
@ -600,7 +600,14 @@ void RendererViewport::draw_viewports() {
// and for our frame timing, mark when we've finished committing our eyes
XRServer::get_singleton()->_mark_commit();
} else {
RSG::storage->render_target_set_external_texture(vp->render_target, 0);
// clear our external texture if set
RSG::storage->render_target_set_external_textures(vp->render_target, RID(), RID());
// @TODO check if our viewport is full screen and is set to output to our display,
// if so we should create an RT that uses our current swap image (maybe set that as our external texture?)
// (Re)create our RT if needed
RSG::storage->render_target_update(vp->render_target);
RSG::scene->set_debug_draw_mode(vp->debug_draw);

View file

@ -361,6 +361,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("texture_create", "format", "view", "data"), &RenderingDevice::_texture_create, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("texture_create_shared", "view", "with_texture"), &RenderingDevice::_texture_create_shared);
ClassDB::bind_method(D_METHOD("texture_create_shared_from_slice", "view", "with_texture", "layer", "mipmap", "slice_type"), &RenderingDevice::_texture_create_shared_from_slice, DEFVAL(TEXTURE_SLICE_2D));
ClassDB::bind_method(D_METHOD("texture_create_from_extension", "type", "format", "samples", "flags", "image", "width", "height", "depth", "layers"), &RenderingDevice::texture_create_from_extension);
ClassDB::bind_method(D_METHOD("texture_update", "texture", "layer", "data", "post_barrier"), &RenderingDevice::texture_update, DEFVAL(BARRIER_MASK_ALL));
ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "layer"), &RenderingDevice::texture_get_data);

View file

@ -496,6 +496,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,

View file

@ -137,7 +137,17 @@ PackedVector3Array XRInterface::get_play_area() const {
// Note implementation is responsible for applying our reference frame and world scale to the raw data.
// `play_area_changed` should be emitted if play area data is available and either the reference frame or world scale changes.
return PackedVector3Array();
};
}
// optional render to external color texture which enhances performance on those platforms that require us to submit our end result into special textures.
RID XRInterface::get_external_color_texture() {
return RID();
}
// optional render to external depth texture which enhances performance on those platforms that require us to submit our end result into special textures.
RID XRInterface::get_external_depth_texture() {
return RID();
}
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool XRInterface::get_anchor_detection_is_enabled() const {

View file

@ -125,6 +125,8 @@ public:
// note, external color/depth/vrs texture support will be added here soon.
virtual RID get_external_color_texture(); /* if applicable return external color texture to render to */
virtual RID get_external_depth_texture(); /* if applicable return external depth texture to render to */
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */
virtual void process() = 0;

View file

@ -52,6 +52,8 @@ void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform");
GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far");
GDVIRTUAL_BIND(_get_external_color_texture);
GDVIRTUAL_BIND(_get_external_depth_texture);
GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect");
GDVIRTUAL_BIND(_process);
@ -333,3 +335,25 @@ RID XRInterfaceExtension::get_render_target_depth(RID p_render_target) {
return rd_scene->render_buffers_get_depth_texture(????????????);
}
*/
// optional render to external color texture which enhances performance on those platforms that require us to submit our end result into special textures.
RID XRInterfaceExtension::get_external_color_texture() {
RID texture;
if (GDVIRTUAL_CALL(_get_external_color_texture, texture)) {
return texture;
}
return RID();
};
// optional render to external depth texture which enhances performance on those platforms that require us to submit our end result into special textures.
RID XRInterfaceExtension::get_external_depth_texture() {
RID texture;
if (GDVIRTUAL_CALL(_get_external_depth_texture, texture)) {
return texture;
}
return RID();
};

View file

@ -108,8 +108,13 @@ public:
GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &);
GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double);
virtual RID get_external_color_texture(); /* if applicable return external color texture to render to */
virtual RID get_external_depth_texture(); /* if applicable return external depth texture to render to */
void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0);
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
GDVIRTUAL0R(RID, _get_external_color_texture);
GDVIRTUAL0R(RID, _get_external_depth_texture);
GDVIRTUAL2(_commit_views, RID, const Rect2 &);
virtual void process() override;