Skip to content

Commit

Permalink
Merge pull request #48207 from BastiaanOlij/multiview_stereoscopic
Browse files Browse the repository at this point in the history
Add stereoscopic rendering through multiview
  • Loading branch information
akien-mga authored Jun 13, 2021
2 parents ef7974f + 15c1a76 commit 4ebf248
Show file tree
Hide file tree
Showing 53 changed files with 1,061 additions and 466 deletions.
3 changes: 3 additions & 0 deletions doc/classes/ProjectSettings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,9 @@
</member>
<member name="rendering/vulkan/staging_buffer/texture_upload_region_size_px" type="int" setter="" getter="" default="64">
</member>
<member name="rendering/xr/enabled" type="bool" setter="" getter="" default="false">
If [code]true[/code], XR support is enabled in Godot, this ensures required shaders are compiled.
</member>
<member name="world/2d/cell_size" type="int" setter="" getter="" default="100">
Cell size used for the 2D hash grid that [VisibilityNotifier2D] uses (in pixels).
</member>
Expand Down
14 changes: 7 additions & 7 deletions doc/classes/XRInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@
If supported, returns the status of our tracking. This will allow you to provide feedback to the user whether there are issues with positional tracking.
</description>
</method>
<method name="get_view_count">
<return type="int">
</return>
<description>
Returns the number of views that need to be rendered for this device. 1 for Monoscopic, 2 for Stereoscopic.
</description>
</method>
<method name="initialize">
<return type="bool">
</return>
Expand All @@ -57,13 +64,6 @@
While currently not used, you can activate additional interfaces. You may wish to do this if you want to track controllers from other platforms. However, at this point in time only one interface can render to an HMD.
</description>
</method>
<method name="is_stereo">
<return type="bool">
</return>
<description>
Returns [code]true[/code] if the current output of this interface is in stereo.
</description>
</method>
<method name="uninitialize">
<return type="void">
</return>
Expand Down
44 changes: 38 additions & 6 deletions drivers/vulkan/rendering_device_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3244,7 +3244,7 @@ bool RenderingDeviceVulkan::texture_is_format_supported_for_usage(DataFormat p_f
/**** ATTACHMENT ****/
/********************/

VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count) {
VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, int *r_color_attachment_count, uint32_t p_view_count) {
Vector<VkAttachmentDescription> attachments;
Vector<VkAttachmentReference> color_references;
Vector<VkAttachmentReference> depth_stencil_references;
Expand Down Expand Up @@ -3469,6 +3469,31 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
render_pass_create_info.dependencyCount = 0;
render_pass_create_info.pDependencies = nullptr;

const uint32_t view_mask = (1 << p_view_count) - 1;
const uint32_t correlation_mask = (1 << p_view_count) - 1;
VkRenderPassMultiviewCreateInfo render_pass_multiview_create_info;

if (p_view_count > 1) {
const VulkanContext::MultiviewCapabilities capabilities = context->get_multiview_capabilities();

// For now this only works with multiview!
ERR_FAIL_COND_V_MSG(!capabilities.is_supported, VK_NULL_HANDLE, "Multiview not supported");

// Make sure we limit this to the number of views we support.
ERR_FAIL_COND_V_MSG(p_view_count > capabilities.max_view_count, VK_NULL_HANDLE, "Hardware does not support requested number of views for Multiview render pass");

render_pass_multiview_create_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO;
render_pass_multiview_create_info.pNext = nullptr;
render_pass_multiview_create_info.subpassCount = 1;
render_pass_multiview_create_info.pViewMasks = &view_mask;
render_pass_multiview_create_info.dependencyCount = 0;
render_pass_multiview_create_info.pViewOffsets = nullptr;
render_pass_multiview_create_info.correlationMaskCount = 1;
render_pass_multiview_create_info.pCorrelationMasks = &correlation_mask;

render_pass_create_info.pNext = &render_pass_multiview_create_info;
}

VkRenderPass render_pass;
VkResult res = vkCreateRenderPass(device, &render_pass_create_info, nullptr, &render_pass);
ERR_FAIL_COND_V_MSG(res, VK_NULL_HANDLE, "vkCreateRenderPass failed with error " + itos(res) + ".");
Expand All @@ -3479,11 +3504,12 @@ VkRenderPass RenderingDeviceVulkan::_render_pass_create(const Vector<AttachmentF
return render_pass;
}

RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format) {
RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_

FramebufferFormatKey key;
key.attachments = p_format;
key.view_count = p_view_count;

const Map<FramebufferFormatKey, FramebufferFormatID>::Element *E = framebuffer_format_cache.find(key);
if (E) {
Expand All @@ -3492,7 +3518,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
}

int color_references;
VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, &color_references); //actions don't matter for this use case
VkRenderPass render_pass = _render_pass_create(p_format, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, INITIAL_ACTION_CLEAR, FINAL_ACTION_READ, &color_references, p_view_count); //actions don't matter for this use case

if (render_pass == VK_NULL_HANDLE) { //was likely invalid
return INVALID_ID;
Expand All @@ -3505,6 +3531,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_format_c
fb_format.color_attachments = color_references;
fb_format.render_pass = render_pass;
fb_format.samples = p_format[0].samples;
fb_format.view_count = p_view_count;
framebuffer_formats[id] = fb_format;
return id;
}
Expand Down Expand Up @@ -3580,11 +3607,12 @@ RID RenderingDeviceVulkan::framebuffer_create_empty(const Size2i &p_size, Textur
framebuffer.format_id = framebuffer_format_create_empty(p_samples);
ERR_FAIL_COND_V(p_format_check != INVALID_FORMAT_ID && framebuffer.format_id != p_format_check, RID());
framebuffer.size = p_size;
framebuffer.view_count = 1;

return framebuffer_owner.make_rid(framebuffer);
}

RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check) {
RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check, uint32_t p_view_count) {
_THREAD_SAFE_METHOD_

Vector<AttachmentFormat> attachments;
Expand All @@ -3594,6 +3622,8 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
Texture *texture = texture_owner.getornull(p_texture_attachments[i]);
ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture index supplied for framebuffer (" + itos(i) + ") is not a valid texture.");

ERR_FAIL_COND_V_MSG(texture->layers != p_view_count, RID(), "Layers of our texture doesn't match view count for this framebuffer");

if (i == 0) {
size.width = texture->width;
size.height = texture->height;
Expand All @@ -3609,7 +3639,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
attachments.push_back(af);
}

FramebufferFormatID format_id = framebuffer_format_create(attachments);
FramebufferFormatID format_id = framebuffer_format_create(attachments, p_view_count);
if (format_id == INVALID_ID) {
return RID();
}
Expand All @@ -3621,6 +3651,7 @@ RID RenderingDeviceVulkan::framebuffer_create(const Vector<RID> &p_texture_attac
framebuffer.format_id = format_id;
framebuffer.texture_ids = p_texture_attachments;
framebuffer.size = size;
framebuffer.view_count = p_view_count;

RID id = framebuffer_owner.make_rid(framebuffer);

Expand Down Expand Up @@ -5904,12 +5935,13 @@ Error RenderingDeviceVulkan::_draw_list_setup_framebuffer(Framebuffer *p_framebu
vk.final_color_action = p_final_color_action;
vk.initial_depth_action = p_initial_depth_action;
vk.final_depth_action = p_final_depth_action;
vk.view_count = p_framebuffer->view_count;

if (!p_framebuffer->framebuffers.has(vk)) {
//need to create this version
Framebuffer::Version version;

version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action);
version.render_pass = _render_pass_create(framebuffer_formats[p_framebuffer->format_id].E->key().attachments, p_initial_color_action, p_final_color_action, p_initial_depth_action, p_final_depth_action, nullptr, p_framebuffer->view_count);

VkFramebufferCreateInfo framebuffer_create_info;
framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
Expand Down
20 changes: 16 additions & 4 deletions drivers/vulkan/rendering_device_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,12 @@ class RenderingDeviceVulkan : public RenderingDevice {

struct FramebufferFormatKey {
Vector<AttachmentFormat> attachments;
uint32_t view_count = 1;
bool operator<(const FramebufferFormatKey &p_key) const {
if (view_count != p_key.view_count) {
return view_count < p_key.view_count;
}

int as = attachments.size();
int bs = p_key.attachments.size();
if (as != bs) {
Expand All @@ -261,7 +266,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
}
};

VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = nullptr);
VkRenderPass _render_pass_create(const Vector<AttachmentFormat> &p_format, InitialAction p_initial_action, FinalAction p_final_action, InitialAction p_initial_depth_action, FinalAction p_final_depthcolor_action, int *r_color_attachment_count = nullptr, uint32_t p_view_count = 1);

// This is a cache and it's never freed, it ensures
// IDs for a given format are always unique.
Expand All @@ -271,6 +276,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
VkRenderPass render_pass = VK_NULL_HANDLE; //here for constructing shaders, never used, see section (7.2. Render Pass Compatibility from Vulkan spec)
int color_attachments = 0; //used for pipeline validation
TextureSamples samples;
uint32_t view_count = 1; // number of views
};

Map<FramebufferFormatID, FramebufferFormat> framebuffer_formats;
Expand All @@ -282,11 +288,16 @@ class RenderingDeviceVulkan : public RenderingDevice {
FinalAction final_color_action;
InitialAction initial_depth_action;
FinalAction final_depth_action;
uint32_t view_count;
bool operator<(const VersionKey &p_key) const {
if (initial_color_action == p_key.initial_color_action) {
if (final_color_action == p_key.final_color_action) {
if (initial_depth_action == p_key.initial_depth_action) {
return final_depth_action < p_key.final_depth_action;
if (final_depth_action == p_key.final_depth_action) {
return view_count < p_key.view_count;
} else {
return final_depth_action < p_key.final_depth_action;
}
} else {
return initial_depth_action < p_key.initial_depth_action;
}
Expand All @@ -309,6 +320,7 @@ class RenderingDeviceVulkan : public RenderingDevice {

Map<VersionKey, Version> framebuffers;
Size2 size;
uint32_t view_count;
};

RID_Owner<Framebuffer, true> framebuffer_owner;
Expand Down Expand Up @@ -938,11 +950,11 @@ class RenderingDeviceVulkan : public RenderingDevice {
/**** FRAMEBUFFER ****/
/*********************/

virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format);
virtual FramebufferFormatID framebuffer_format_create(const Vector<AttachmentFormat> &p_format, uint32_t p_view_count = 1);
virtual FramebufferFormatID framebuffer_format_create_empty(TextureSamples p_samples = TEXTURE_SAMPLES_1);
virtual TextureSamples framebuffer_format_get_texture_samples(FramebufferFormatID p_format);

virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID);
virtual RID framebuffer_create(const Vector<RID> &p_texture_attachments, FramebufferFormatID p_format_check = INVALID_ID, uint32_t p_view_count = 1);
virtual RID framebuffer_create_empty(const Size2i &p_size, TextureSamples p_samples = TEXTURE_SAMPLES_1, FramebufferFormatID p_format_check = INVALID_ID);

virtual FramebufferFormatID framebuffer_get_format(RID p_framebuffer);
Expand Down
47 changes: 45 additions & 2 deletions drivers/vulkan/vulkan_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ Error VulkanContext::_initialize_extensions() {
extension_names[enabled_extension_count++] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME;
enabled_debug_utils = true;
}
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 @@ -504,6 +507,8 @@ Error VulkanContext::_check_capabilities() {

// assume not supported until proven otherwise
multiview_capabilities.is_supported = false;
multiview_capabilities.geometry_shader_is_supported = false;
multiview_capabilities.tessellation_shader_is_supported = false;
multiview_capabilities.max_view_count = 0;
multiview_capabilities.max_instance_count = 0;
subgroup_capabilities.size = 0;
Expand All @@ -529,7 +534,8 @@ Error VulkanContext::_check_capabilities() {

device_features_func(gpu, &device_features);
multiview_capabilities.is_supported = multiview_features.multiview;
// For now we ignore if multiview is available in geometry and tessellation as we do not currently support those
multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
}

// check extended properties
Expand Down Expand Up @@ -573,7 +579,7 @@ Error VulkanContext::_check_capabilities() {

#ifdef DEBUG_ENABLED
print_line("- Vulkan multiview supported:");
print_line(" max views: " + itos(multiview_capabilities.max_view_count));
print_line(" max view count: " + itos(multiview_capabilities.max_view_count));
print_line(" max instances: " + itos(multiview_capabilities.max_instance_count));
} else {
print_line("- Vulkan multiview not supported");
Expand Down Expand Up @@ -772,6 +778,10 @@ Error VulkanContext::_create_physical_device() {
swapchainExtFound = 1;
extension_names[enabled_extension_count++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
}
if (!strcmp(VK_KHR_MULTIVIEW_EXTENSION_NAME, device_extensions[i].extensionName)) {
// 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 Expand Up @@ -964,6 +974,39 @@ Error VulkanContext::_create_device() {
queues[1].flags = 0;
sdevice.queueCreateInfoCount = 2;
}

#ifdef VK_VERSION_1_2
VkPhysicalDeviceVulkan11Features vulkan11features;

vulkan11features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
vulkan11features.pNext = nullptr;
// !BAS! Need to figure out which ones of these we want enabled...
vulkan11features.storageBuffer16BitAccess = 0;
vulkan11features.uniformAndStorageBuffer16BitAccess = 0;
vulkan11features.storagePushConstant16 = 0;
vulkan11features.storageInputOutput16 = 0;
vulkan11features.multiview = multiview_capabilities.is_supported;
vulkan11features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
vulkan11features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;
vulkan11features.variablePointersStorageBuffer = 0;
vulkan11features.variablePointers = 0;
vulkan11features.protectedMemory = 0;
vulkan11features.samplerYcbcrConversion = 0;
vulkan11features.shaderDrawParameters = 0;

sdevice.pNext = &vulkan11features;
#elif VK_VERSION_1_1
VkPhysicalDeviceMultiviewFeatures multiview_features;

multiview_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
multiview_features.pNext = nullptr;
multiview_features.multiview = multiview_capabilities.is_supported;
multiview_features.multiviewGeometryShader = multiview_capabilities.geometry_shader_is_supported;
multiview_features.multiviewTessellationShader = multiview_capabilities.tessellation_shader_is_supported;

sdevice.pNext = &multiview_features;
#endif

err = vkCreateDevice(gpu, &sdevice, nullptr, &device);
ERR_FAIL_COND_V(err, ERR_CANT_CREATE);

Expand Down
6 changes: 4 additions & 2 deletions drivers/vulkan/vulkan_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ class VulkanContext {

struct MultiviewCapabilities {
bool is_supported;
int32_t max_view_count;
int32_t max_instance_count;
bool geometry_shader_is_supported;
bool tessellation_shader_is_supported;
uint32_t max_view_count;
uint32_t max_instance_count;
};

private:
Expand Down
6 changes: 3 additions & 3 deletions modules/gdnative/gdnative_api.json
Original file line number Diff line number Diff line change
Expand Up @@ -5068,7 +5068,7 @@
},
{
"name": "godot_xr_get_worldscale",
"return_type": "godot_float",
"return_type": "godot_real_t",
"arguments": []
},
{
Expand Down Expand Up @@ -5189,7 +5189,7 @@
"p_exis"
],
[
"godot_float",
"godot_real_t",
"p_value"
],
[
Expand All @@ -5200,7 +5200,7 @@
},
{
"name": "godot_xr_get_controller_rumble",
"return_type": "godot_float",
"return_type": "godot_real_t",
"arguments": [
[
"godot_int",
Expand Down
Loading

0 comments on commit 4ebf248

Please sign in to comment.