Merge bf3983c318
into 171a69757f
This commit is contained in:
commit
7e439b75ad
|
@ -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" />
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
438
modules/gdnative/xr/xr_interface_gdnative.cpp
Normal file
438
modules/gdnative/xr/xr_interface_gdnative.cpp
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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 {}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue