Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement external texture support for XR plugins that require render… #51179

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/classes/RenderingDevice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
10 changes: 10 additions & 0 deletions doc/classes/XRInterfaceExtension.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
111 changes: 9 additions & 102 deletions drivers/gles3/rasterizer_storage_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3630,6 +3630,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;
Expand Down Expand Up @@ -3679,113 +3685,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);

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;
// TODO re-implement this once stereo support has been added

// 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) {
Expand Down
3 changes: 2 additions & 1 deletion drivers/gles3/rasterizer_storage_gles3.h
Original file line number Diff line number Diff line change
Expand Up @@ -1256,10 +1256,11 @@ class RasterizerStorageGLES3 : public RendererStorage {
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;
Expand Down
120 changes: 119 additions & 1 deletion drivers/vulkan/rendering_device_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2170,6 +2170,124 @@ 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;
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_UNORM);
texture.allowed_shared_formats.push_back(RD::DATA_FORMAT_R8G8B8A8_SRGB);

// 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, maybe 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, uint32_t p_mipmaps, TextureSliceType p_slice_type) {
_THREAD_SAFE_METHOD_

Expand Down Expand Up @@ -8720,7 +8838,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);
Expand Down
1 change: 1 addition & 0 deletions drivers/vulkan/rendering_device_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, uint32_t p_mipmaps = 1, 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);
Expand Down
2 changes: 2 additions & 0 deletions drivers/vulkan/vulkan_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ 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;
}

if (enabled_extension_count >= MAX_EXTENSIONS) {
free(instance_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
Expand Down Expand Up @@ -801,6 +802,7 @@ Error VulkanContext::_create_physical_device() {
// if multiview is supported, enable it
extension_names[enabled_extension_count++] = VK_KHR_MULTIVIEW_EXTENSION_NAME;
}

if (enabled_extension_count >= MAX_EXTENSIONS) {
free(device_extensions);
ERR_FAIL_V_MSG(ERR_BUG, "Enabled extension count reaches MAX_EXTENSIONS, BUG");
Expand Down
3 changes: 2 additions & 1 deletion servers/rendering/rasterizer_dummy.h
Original file line number Diff line number Diff line change
Expand Up @@ -661,10 +661,11 @@ class RasterizerStorageDummy : public RendererStorage {
/* 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 {}
Expand Down
Loading