summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/unix/ip_unix.cpp12
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp185
-rw-r--r--drivers/vulkan/rendering_device_vulkan.h14
-rw-r--r--drivers/vulkan/vulkan_context.cpp56
-rw-r--r--drivers/vulkan/vulkan_context.h6
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();
};