diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/unix/ip_unix.cpp | 12 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.cpp | 185 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.h | 14 | ||||
-rw-r--r-- | drivers/vulkan/vulkan_context.cpp | 56 | ||||
-rw-r--r-- | drivers/vulkan/vulkan_context.h | 6 |
5 files changed, 238 insertions, 35 deletions
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index e8f8ae4717..8a880ab9c8 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -41,19 +41,7 @@ #include <windows.h> #include <ws2tcpip.h> #ifndef UWP_ENABLED -#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4) -// MinGW-w64 on Ubuntu 12.04 (our Travis build env) has bugs in this code where -// some includes are missing in dependencies of iphlpapi.h for WINVER >= 0x0600 (Vista). -// We don't use this Vista code for now, so working it around by disabling it. -// MinGW-w64 >= 4.0 seems to be better judging by its headers. -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 // Windows XP, disable Vista API #include <iphlpapi.h> -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 // Re-enable Vista API -#else -#include <iphlpapi.h> -#endif // MINGW hack #endif #else // UNIX #include <netdb.h> diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 2a8d4fcded..5bf3bbf8a4 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -2032,7 +2032,7 @@ RID RenderingDeviceVulkan::texture_create(const TextureFormat &p_format, const T if (p_data.size()) { for (uint32_t i = 0; i < image_create_info.arrayLayers; i++) { - texture_update(id, i, p_data[i]); + _texture_update(id, i, p_data[i], RD::BARRIER_MASK_ALL, true); } } return id; @@ -2279,10 +2279,14 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p } Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier) { + return _texture_update(p_texture, p_layer, p_data, p_post_barrier, false); +} + +Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue) { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V_MSG(draw_list || compute_list, ERR_INVALID_PARAMETER, - "Updating textures in is forbidden during creation of a draw or compute list"); + ERR_FAIL_COND_V_MSG((draw_list || compute_list) && !p_use_setup_queue, ERR_INVALID_PARAMETER, + "Updating textures is forbidden during creation of a draw or compute list"); Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER); @@ -2323,7 +2327,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con const uint8_t *r = p_data.ptr(); - VkCommandBuffer command_buffer = p_post_barrier ? frames[frame].draw_command_buffer : frames[frame].setup_command_buffer; + VkCommandBuffer command_buffer = p_use_setup_queue ? frames[frame].setup_command_buffer : frames[frame].draw_command_buffer; //barrier to transfer { @@ -2376,7 +2380,7 @@ Error RenderingDeviceVulkan::texture_update(RID p_texture, uint32_t p_layer, con to_allocate >>= get_compressed_image_format_pixel_rshift(texture->format); uint32_t alloc_offset, alloc_size; - Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, p_post_barrier); + Error err = _staging_buffer_allocate(to_allocate, required_align, alloc_offset, alloc_size, false, !p_use_setup_queue); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); uint8_t *write_ptr; @@ -4370,6 +4374,8 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages uint32_t stages_processed = 0; + Vector<Shader::SpecializationConstant> specialization_constants; + bool is_compute = false; uint32_t compute_local_size[3] = { 0, 0, 0 }; @@ -4556,6 +4562,60 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages } } + { + //specialization constants + + uint32_t sc_count = 0; + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, nullptr); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed enumerating specialization constants."); + + if (sc_count) { + Vector<SpvReflectSpecializationConstant *> spec_constants; + spec_constants.resize(sc_count); + + result = spvReflectEnumerateSpecializationConstants(&module, &sc_count, spec_constants.ptrw()); + ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, RID(), + "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_stages[i].shader_stage]) + "' failed obtaining specialization constants."); + + for (uint32_t j = 0; j < sc_count; j++) { + int32_t existing = -1; + Shader::SpecializationConstant sconst; + sconst.constant.constant_id = spec_constants[j]->constant_id; + switch (spec_constants[j]->constant_type) { + case SPV_REFLECT_SPECIALIZATION_CONSTANT_BOOL: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL; + sconst.constant.bool_value = spec_constants[j]->default_value.int_bool_value != 0; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_INT: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_INT; + sconst.constant.int_value = spec_constants[j]->default_value.int_bool_value; + } break; + case SPV_REFLECT_SPECIALIZATION_CONSTANT_FLOAT: { + sconst.constant.type = PIPELINE_SPECIALIZATION_CONSTANT_TYPE_FLOAT; + sconst.constant.float_value = spec_constants[j]->default_value.float_value; + } break; + } + sconst.stage_flags = 1 << p_stages[i].shader_stage; + + for (int k = 0; k < specialization_constants.size(); k++) { + if (specialization_constants[k].constant.constant_id == sconst.constant.constant_id) { + ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.type != sconst.constant.type, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their types differ."); + ERR_FAIL_COND_V_MSG(specialization_constants[k].constant.int_value != sconst.constant.int_value, RID(), "More than one specialization constant used for id (" + itos(sconst.constant.constant_id) + "), but their default values differ."); + existing = k; + break; + } + } + + if (existing > 0) { + specialization_constants.write[existing].stage_flags |= sconst.stage_flags; + } else { + specialization_constants.push_back(sconst); + } + } + } + } + if (stage == SHADER_STAGE_VERTEX) { uint32_t iv_count = 0; result = spvReflectEnumerateInputVariables(&module, &iv_count, nullptr); @@ -4652,6 +4712,7 @@ RID RenderingDeviceVulkan::shader_create(const Vector<ShaderStageData> &p_stages shader.compute_local_size[0] = compute_local_size[0]; shader.compute_local_size[1] = compute_local_size[1]; shader.compute_local_size[2] = compute_local_size[2]; + shader.specialization_constants = specialization_constants; String error_text; @@ -5501,6 +5562,13 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) { return uniform_set_owner.owns(p_uniform_set); } +void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) { + UniformSet *us = uniform_set_owner.getornull(p_uniform_set); + ERR_FAIL_COND(!us); + us->invalidated_callback = p_callback; + us->invalidated_callback_userdata = p_userdata; +} + Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier) { _THREAD_SAFE_METHOD_ @@ -5640,7 +5708,7 @@ Vector<uint8_t> RenderingDeviceVulkan::buffer_get_data(RID p_buffer) { /**** RENDER PIPELINE ****/ /*************************/ -RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass) { +RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags, uint32_t p_for_render_pass, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { _THREAD_SAFE_METHOD_ //needs a shader @@ -5740,7 +5808,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma tessellation_create_info.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; tessellation_create_info.pNext = nullptr; tessellation_create_info.flags = 0; - ERR_FAIL_COND_V(p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize, RID()); + ERR_FAIL_COND_V(limits.maxTessellationPatchSize > 0 && (p_rasterization_state.patch_control_points < 1 || p_rasterization_state.patch_control_points > limits.maxTessellationPatchSize), RID()); tessellation_create_info.patchControlPoints = p_rasterization_state.patch_control_points; VkPipelineViewportStateCreateInfo viewport_state_create_info; @@ -5958,8 +6026,63 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma graphics_pipeline_create_info.pNext = nullptr; graphics_pipeline_create_info.flags = 0; - graphics_pipeline_create_info.stageCount = shader->pipeline_stages.size(); - graphics_pipeline_create_info.pStages = shader->pipeline_stages.ptr(); + Vector<VkPipelineShaderStageCreateInfo> pipeline_stages = shader->pipeline_stages; + Vector<VkSpecializationInfo> specialization_info; + Vector<Vector<VkSpecializationMapEntry>> specialization_map_entries; + Vector<uint32_t> specialization_constant_data; + + if (shader->specialization_constants.size()) { + specialization_constant_data.resize(shader->specialization_constants.size()); + uint32_t *data_ptr = specialization_constant_data.ptrw(); + specialization_info.resize(pipeline_stages.size()); + specialization_map_entries.resize(pipeline_stages.size()); + for (int i = 0; i < shader->specialization_constants.size(); i++) { + //see if overriden + const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; + data_ptr[i] = sc.constant.int_value; //just copy the 32 bits + + for (int j = 0; j < p_specialization_constants.size(); j++) { + const PipelineSpecializationConstant &psc = p_specialization_constants[j]; + if (psc.constant_id == sc.constant.constant_id) { + ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); + data_ptr[i] = psc.int_value; + break; + } + } + + VkSpecializationMapEntry entry; + + entry.constantID = sc.constant.constant_id; + entry.offset = i * sizeof(uint32_t); + entry.size = sizeof(uint32_t); + + for (int j = 0; j < SHADER_STAGE_MAX; j++) { + if (sc.stage_flags & (1 << j)) { + VkShaderStageFlagBits stage = shader_stage_masks[j]; + for (int k = 0; k < pipeline_stages.size(); k++) { + if (pipeline_stages[k].stage == stage) { + specialization_map_entries.write[k].push_back(entry); + } + } + } + } + } + + for (int i = 0; i < pipeline_stages.size(); i++) { + if (specialization_map_entries[i].size()) { + specialization_info.write[i].dataSize = specialization_constant_data.size() * sizeof(uint32_t); + specialization_info.write[i].pData = data_ptr; + specialization_info.write[i].mapEntryCount = specialization_map_entries[i].size(); + specialization_info.write[i].pMapEntries = specialization_map_entries[i].ptr(); + + pipeline_stages.write[i].pSpecializationInfo = specialization_info.ptr() + i; + } + } + } + + graphics_pipeline_create_info.stageCount = pipeline_stages.size(); + graphics_pipeline_create_info.pStages = pipeline_stages.ptr(); + graphics_pipeline_create_info.pVertexInputState = &pipeline_vertex_input_state_create_info; graphics_pipeline_create_info.pInputAssemblyState = &input_assembly_create_info; graphics_pipeline_create_info.pTessellationState = &tessellation_create_info; @@ -6028,7 +6151,7 @@ bool RenderingDeviceVulkan::render_pipeline_is_valid(RID p_pipeline) { /**** COMPUTE PIPELINE ****/ /**************************/ -RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { +RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants) { _THREAD_SAFE_METHOD_ //needs a shader @@ -6050,6 +6173,44 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader) { compute_pipeline_create_info.basePipelineHandle = VK_NULL_HANDLE; compute_pipeline_create_info.basePipelineIndex = 0; + VkSpecializationInfo specialization_info; + Vector<VkSpecializationMapEntry> specialization_map_entries; + Vector<uint32_t> specialization_constant_data; + + if (shader->specialization_constants.size()) { + specialization_constant_data.resize(shader->specialization_constants.size()); + uint32_t *data_ptr = specialization_constant_data.ptrw(); + for (int i = 0; i < shader->specialization_constants.size(); i++) { + //see if overriden + const Shader::SpecializationConstant &sc = shader->specialization_constants[i]; + data_ptr[i] = sc.constant.int_value; //just copy the 32 bits + + for (int j = 0; j < p_specialization_constants.size(); j++) { + const PipelineSpecializationConstant &psc = p_specialization_constants[j]; + if (psc.constant_id == sc.constant.constant_id) { + ERR_FAIL_COND_V_MSG(psc.type != sc.constant.type, RID(), "Specialization constant provided for id (" + itos(sc.constant.constant_id) + ") is of the wrong type."); + data_ptr[i] = sc.constant.int_value; + break; + } + } + + VkSpecializationMapEntry entry; + + entry.constantID = sc.constant.constant_id; + entry.offset = i * sizeof(uint32_t); + entry.size = sizeof(uint32_t); + + specialization_map_entries.push_back(entry); + } + + specialization_info.dataSize = specialization_constant_data.size() * sizeof(uint32_t); + specialization_info.pData = data_ptr; + specialization_info.mapEntryCount = specialization_map_entries.size(); + specialization_info.pMapEntries = specialization_map_entries.ptr(); + + compute_pipeline_create_info.stage.pSpecializationInfo = &specialization_info; + } + ComputePipeline pipeline; VkResult err = vkCreateComputePipelines(device, VK_NULL_HANDLE, 1, &compute_pipeline_create_info, nullptr, &pipeline.pipeline); ERR_FAIL_COND_V_MSG(err, RID(), "vkCreateComputePipelines failed with error " + itos(err) + "."); @@ -7840,6 +8001,10 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) { } else if (uniform_set_owner.owns(p_id)) { UniformSet *uniform_set = uniform_set_owner.getornull(p_id); frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set); + if (uniform_set->invalidated_callback != nullptr) { + uniform_set->invalidated_callback(p_id, uniform_set->invalidated_callback_userdata); + } + uniform_set_owner.free(p_id); } else if (render_pipeline_owner.owns(p_id)) { RenderPipeline *pipeline = render_pipeline_owner.getornull(p_id); diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h index 1f86fe9e48..8b95ff43b8 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -156,6 +156,7 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t texture_upload_region_size_px = 0; Vector<uint8_t> _texture_get_data_from_image(Texture *tex, VkImage p_image, VmaAllocation p_allocation, uint32_t p_layer, bool p_2d = false); + Error _texture_update(RID p_texture, uint32_t p_layer, const Vector<uint8_t> &p_data, uint32_t p_post_barrier, bool p_use_setup_queue); /*****************/ /**** SAMPLER ****/ @@ -622,11 +623,17 @@ class RenderingDeviceVulkan : public RenderingDevice { uint32_t compute_local_size[3] = { 0, 0, 0 }; + struct SpecializationConstant { + PipelineSpecializationConstant constant; + uint32_t stage_flags = 0; + }; + bool is_compute = false; int max_output = 0; Vector<Set> sets; Vector<uint32_t> set_formats; Vector<VkPipelineShaderStageCreateInfo> pipeline_stages; + Vector<SpecializationConstant> specialization_constants; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; }; @@ -731,6 +738,8 @@ class RenderingDeviceVulkan : public RenderingDevice { LocalVector<AttachableTexture> attachable_textures; //used for validation Vector<Texture *> mutable_sampled_textures; //used for layout change Vector<Texture *> mutable_storage_textures; //used for layout change + UniformSetInvalidatedCallback invalidated_callback = nullptr; + void *invalidated_callback_userdata = nullptr; }; RID_Owner<UniformSet, true> uniform_set_owner; @@ -1087,6 +1096,7 @@ public: virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set); virtual bool uniform_set_is_valid(RID p_uniform_set); + virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata); virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL); @@ -1096,14 +1106,14 @@ public: /**** RENDER PIPELINE ****/ /*************************/ - virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0); + virtual RID render_pipeline_create(RID p_shader, FramebufferFormatID p_framebuffer_format, VertexFormatID p_vertex_format, RenderPrimitive p_render_primitive, const PipelineRasterizationState &p_rasterization_state, const PipelineMultisampleState &p_multisample_state, const PipelineDepthStencilState &p_depth_stencil_state, const PipelineColorBlendState &p_blend_state, int p_dynamic_state_flags = 0, uint32_t p_for_render_pass = 0, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()); virtual bool render_pipeline_is_valid(RID p_pipeline); /**************************/ /**** COMPUTE PIPELINE ****/ /**************************/ - virtual RID compute_pipeline_create(RID p_shader); + virtual RID compute_pipeline_create(RID p_shader, const Vector<PipelineSpecializationConstant> &p_specialization_constants = Vector<PipelineSpecializationConstant>()); virtual bool compute_pipeline_is_valid(RID p_pipeline); /****************/ diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp index 74bd938822..d35c519320 100644 --- a/drivers/vulkan/vulkan_context.cpp +++ b/drivers/vulkan/vulkan_context.cpp @@ -1189,7 +1189,7 @@ bool VulkanContext::_use_validation_layers() { return Engine::get_singleton()->is_validation_layers_enabled(); } -Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height) { +Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height) { ERR_FAIL_COND_V(windows.has(p_window_id), ERR_INVALID_PARAMETER); if (!queues_initialized) { @@ -1217,6 +1217,7 @@ Error VulkanContext::_window_create(DisplayServer::WindowID p_window_id, VkSurfa window.surface = p_surface; window.width = p_width; window.height = p_height; + window.vsync_mode = p_vsync_mode; Error err = _update_swap_chain(&window); ERR_FAIL_COND_V(err != OK, ERR_CANT_CREATE); @@ -1360,7 +1361,6 @@ Error VulkanContext::_update_swap_chain(Window *window) { } // The FIFO present mode is guaranteed by the spec to be supported // and to have no tearing. It's a great default present mode to use. - VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; // There are times when you may wish to use another present mode. The // following code shows how to select them, and the comments provide some @@ -1389,16 +1389,41 @@ Error VulkanContext::_update_swap_chain(Window *window) { // the application wants the late image to be immediately displayed, even // though that may mean some tearing. - if (window->presentMode != swapchainPresentMode) { - for (size_t i = 0; i < presentModeCount; ++i) { - if (presentModes[i] == window->presentMode) { - swapchainPresentMode = window->presentMode; - break; - } + VkPresentModeKHR requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR; + switch (window->vsync_mode) { + case DisplayServer::VSYNC_MAILBOX: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_MAILBOX_KHR; + break; + case DisplayServer::VSYNC_ADAPTIVE: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_RELAXED_KHR; + break; + case DisplayServer::VSYNC_ENABLED: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_FIFO_KHR; + break; + case DisplayServer::VSYNC_DISABLED: + requested_present_mode = VkPresentModeKHR::VK_PRESENT_MODE_IMMEDIATE_KHR; + break; + } + + // Check if the requested mode is available. + bool present_mode_available = false; + for (uint32_t i = 0; i < presentModeCount; i++) { + if (presentModes[i] == requested_present_mode) { + present_mode_available = true; } } + + // Set the windows present mode if it is available, otherwise FIFO is used (guaranteed supported). + if (present_mode_available) { + window->presentMode = requested_present_mode; + } else { + WARN_PRINT("Requested VSync mode is not available!"); + window->vsync_mode = DisplayServer::VSYNC_ENABLED; //Set to default + } + + print_verbose("Using present mode: " + String(string_VkPresentModeKHR(window->presentMode))); + free(presentModes); - ERR_FAIL_COND_V_MSG(swapchainPresentMode != window->presentMode, ERR_CANT_CREATE, "Present mode specified is not supported\n"); // Determine the number of VkImages to use in the swap chain. // Application desires to acquire 3 images at a time for triple @@ -1455,7 +1480,7 @@ Error VulkanContext::_update_swap_chain(Window *window) { /*pQueueFamilyIndices*/ nullptr, /*preTransform*/ (VkSurfaceTransformFlagBitsKHR)preTransform, /*compositeAlpha*/ compositeAlpha, - /*presentMode*/ swapchainPresentMode, + /*presentMode*/ window->presentMode, /*clipped*/ true, /*oldSwapchain*/ VK_NULL_HANDLE, }; @@ -2162,6 +2187,17 @@ String VulkanContext::get_device_pipeline_cache_uuid() const { return pipeline_cache_id; } +DisplayServer::VSyncMode VulkanContext::get_vsync_mode(DisplayServer::WindowID p_window) const { + ERR_FAIL_COND_V_MSG(!windows.has(p_window), DisplayServer::VSYNC_ENABLED, "Could not get VSync mode for window with WindowID " + itos(p_window) + " because it does not exist."); + return windows[p_window].vsync_mode; +} + +void VulkanContext::set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode) { + ERR_FAIL_COND_MSG(!windows.has(p_window), "Could not set VSync mode for window with WindowID " + itos(p_window) + " because it does not exist."); + windows[p_window].vsync_mode = p_mode; + _update_swap_chain(&windows[p_window]); +} + VulkanContext::VulkanContext() { command_buffer_queue.resize(1); // First one is always the setup command. command_buffer_queue.write[0] = nullptr; diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h index 8f1005d07f..83e9524046 100644 --- a/drivers/vulkan/vulkan_context.h +++ b/drivers/vulkan/vulkan_context.h @@ -124,6 +124,7 @@ private: uint32_t current_buffer = 0; int width = 0; int height = 0; + DisplayServer::VSyncMode vsync_mode = DisplayServer::VSYNC_ENABLED; VkCommandPool present_cmd_pool = VK_NULL_HANDLE; // For separate present queue. VkRenderPass render_pass = VK_NULL_HANDLE; }; @@ -222,7 +223,7 @@ private: protected: virtual const char *_get_platform_surface_extension() const = 0; - virtual Error _window_create(DisplayServer::WindowID p_window_id, VkSurfaceKHR p_surface, int p_width, int p_height); + virtual Error _window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, VkSurfaceKHR p_surface, int p_width, int p_height); virtual bool _use_validation_layers(); @@ -276,6 +277,9 @@ public: String get_device_name() const; String get_device_pipeline_cache_uuid() const; + void set_vsync_mode(DisplayServer::WindowID p_window, DisplayServer::VSyncMode p_mode); + DisplayServer::VSyncMode get_vsync_mode(DisplayServer::WindowID p_window = 0) const; + VulkanContext(); virtual ~VulkanContext(); }; |