summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.cpp46
-rw-r--r--drivers/d3d12/rendering_device_driver_d3d12.h3
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp17
-rw-r--r--drivers/gles3/rasterizer_gles3.h1
-rw-r--r--drivers/gles3/shaders/canvas.glsl43
-rw-r--r--drivers/gles3/shaders/scene.glsl5
-rw-r--r--drivers/gles3/storage/config.cpp5
-rw-r--r--drivers/gles3/storage/config.h2
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.cpp223
-rw-r--r--drivers/vulkan/rendering_device_driver_vulkan.h6
10 files changed, 210 insertions, 141 deletions
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp
index 6517b4e91b..8c92737374 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.cpp
+++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp
@@ -1955,48 +1955,44 @@ RDD::CommandQueueID RenderingDeviceDriverD3D12::command_queue_create(CommandQueu
return CommandQueueID(command_queue);
}
-Error RenderingDeviceDriverD3D12::command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) {
+Error RenderingDeviceDriverD3D12::command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) {
CommandQueueInfo *command_queue = (CommandQueueInfo *)(p_cmd_queue.id);
for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) {
const SemaphoreInfo *semaphore = (const SemaphoreInfo *)(p_wait_semaphores[i].id);
command_queue->d3d_queue->Wait(semaphore->d3d_fence.Get(), semaphore->fence_value);
}
- thread_local LocalVector<ID3D12CommandList *> command_lists;
- command_lists.resize(p_cmd_buffers.size());
- for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {
- const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffers[i].id);
- command_lists[i] = cmd_buf_info->cmd_list.Get();
- }
+ if (p_cmd_buffers.size() > 0) {
+ thread_local LocalVector<ID3D12CommandList *> command_lists;
+ command_lists.resize(p_cmd_buffers.size());
+ for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {
+ const CommandBufferInfo *cmd_buf_info = (const CommandBufferInfo *)(p_cmd_buffers[i].id);
+ command_lists[i] = cmd_buf_info->cmd_list.Get();
+ }
- command_queue->d3d_queue->ExecuteCommandLists(command_lists.size(), command_lists.ptr());
+ command_queue->d3d_queue->ExecuteCommandLists(command_lists.size(), command_lists.ptr());
- for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) {
- SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_signal_semaphores[i].id);
- semaphore->fence_value++;
- command_queue->d3d_queue->Signal(semaphore->d3d_fence.Get(), semaphore->fence_value);
- }
+ for (uint32_t i = 0; i < p_cmd_semaphores.size(); i++) {
+ SemaphoreInfo *semaphore = (SemaphoreInfo *)(p_cmd_semaphores[i].id);
+ semaphore->fence_value++;
+ command_queue->d3d_queue->Signal(semaphore->d3d_fence.Get(), semaphore->fence_value);
+ }
- if (p_signal_fence) {
- FenceInfo *fence = (FenceInfo *)(p_signal_fence.id);
- fence->fence_value++;
- command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value);
- fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle);
+ if (p_cmd_fence) {
+ FenceInfo *fence = (FenceInfo *)(p_cmd_fence.id);
+ fence->fence_value++;
+ command_queue->d3d_queue->Signal(fence->d3d_fence.Get(), fence->fence_value);
+ fence->d3d_fence->SetEventOnCompletion(fence->fence_value, fence->event_handle);
+ }
}
- return OK;
-}
-
-Error RenderingDeviceDriverD3D12::command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) {
- // D3D12 does not require waiting for the command queue's semaphores to handle presentation.
- // We just present the swap chains that were specified and ignore the command queue and the semaphores.
HRESULT res;
bool any_present_failed = false;
for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
res = swap_chain->d3d_swap_chain->Present(swap_chain->sync_interval, swap_chain->present_flags);
if (!SUCCEEDED(res)) {
- print_verbose("D3D12: Presenting swapchain failed with error " + vformat("0x%08ux", (uint64_t)res) + ".");
+ print_verbose(vformat("D3D12: Presenting swapchain failed with error 0x%08ux.", (uint64_t)res));
any_present_failed = true;
}
}
diff --git a/drivers/d3d12/rendering_device_driver_d3d12.h b/drivers/d3d12/rendering_device_driver_d3d12.h
index 595ee30966..06d5cb65c4 100644
--- a/drivers/d3d12/rendering_device_driver_d3d12.h
+++ b/drivers/d3d12/rendering_device_driver_d3d12.h
@@ -413,8 +413,7 @@ private:
public:
virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override;
- virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) override;
- virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) override;
+ virtual Error command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) override;
virtual void command_queue_free(CommandQueueID p_cmd_queue) override;
private:
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 14ef0f40cf..da2320c23d 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -194,6 +194,11 @@ typedef void(GLAPIENTRY *DebugMessageCallbackARB)(DEBUGPROCARB callback, const v
void RasterizerGLES3::initialize() {
Engine::get_singleton()->print_header(vformat("OpenGL API %s - Compatibility - Using Device: %s - %s", RS::get_singleton()->get_video_adapter_api_version(), RS::get_singleton()->get_video_adapter_vendor(), RS::get_singleton()->get_video_adapter_name()));
+
+ // FLIP XY Bug: Are more devices affected?
+ // Confirmed so far: all Adreno 3xx
+ // ok on some tested Adreno devices: 4xx, 5xx and 6xx
+ flip_xy_bugfix = GLES3::Config::get_singleton()->adreno_3xx_compatibility;
}
void RasterizerGLES3::finalize() {
@@ -398,8 +403,18 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
}
Vector2i screen_rect_end = p_screen_rect.get_end();
+
+ // Adreno (TM) 3xx devices have a bug that create wrong Landscape rotation of 180 degree
+ // Reversing both the X and Y axis is equivalent to rotating 180 degrees
+ bool flip_x = false;
+ if (flip_xy_bugfix && screen_rect_end.x > screen_rect_end.y) {
+ flip_y = !flip_y;
+ flip_x = !flip_x;
+ }
+
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y,
- p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y, screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y,
+ flip_x ? screen_rect_end.x : p_screen_rect.position.x, flip_y ? screen_rect_end.y : p_screen_rect.position.y,
+ flip_x ? p_screen_rect.position.x : screen_rect_end.x, flip_y ? p_screen_rect.position.y : screen_rect_end.y,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
if (read_fbo != 0) {
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index fc1315035b..8d52dc2365 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -55,6 +55,7 @@ private:
float delta = 0;
double time_total = 0.0;
+ bool flip_xy_bugfix = false;
static bool gles_over_gl;
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 80e28cf9fc..8da7d7dc80 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -187,8 +187,31 @@ void main() {
#endif // !USE_INSTANCING
#else // !USE_ATTRIBUTES
- vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0));
- vec2 vertex_base = vertex_base_arr[gl_VertexID % 6];
+
+ // crash on Adreno 320/330
+ //vec2 vertex_base_arr[6] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 1.0));
+ //vec2 vertex_base = vertex_base_arr[gl_VertexID % 6];
+ //-----------------------------------------
+ // ID | 0 | 1 | 2 | 3 | 4 | 5 |
+ //-----------------------------------------
+ // X | 0.0 | 0.0 | 1.0 | 1.0 | 0.0 | 1.0 |
+ // Y | 0.0 | 1.0 | 1.0 | 0.0 | 0.0 | 1.0 |
+ //-----------------------------------------
+ // no crash or freeze on all Adreno 3xx with 'if / else if' and slightly faster!
+ int vertex_id = gl_VertexID % 6;
+ vec2 vertex_base;
+ if (vertex_id == 0)
+ vertex_base = vec2(0.0, 0.0);
+ else if (vertex_id == 1)
+ vertex_base = vec2(0.0, 1.0);
+ else if (vertex_id == 2)
+ vertex_base = vec2(1.0, 1.0);
+ else if (vertex_id == 3)
+ vertex_base = vec2(1.0, 0.0);
+ else if (vertex_id == 4)
+ vertex_base = vec2(0.0, 0.0);
+ else if (vertex_id == 5)
+ vertex_base = vec2(1.0, 1.0);
vec2 uv = read_draw_data_src_rect.xy + abs(read_draw_data_src_rect.zw) * ((read_draw_data_flags & FLAGS_TRANSPOSE_RECT) != uint(0) ? vertex_base.yx : vertex_base.xy);
vec4 color = read_draw_data_modulation;
@@ -475,16 +498,12 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
void light_blend_compute(uint light_base, vec4 light_color, inout vec3 color) {
uint blend_mode = light_array[light_base].flags & LIGHT_FLAGS_BLEND_MASK;
- switch (blend_mode) {
- case LIGHT_FLAGS_BLEND_MODE_ADD: {
- color.rgb += light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_SUB: {
- color.rgb -= light_color.rgb * light_color.a;
- } break;
- case LIGHT_FLAGS_BLEND_MODE_MIX: {
- color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
- } break;
+ if (blend_mode == LIGHT_FLAGS_BLEND_MODE_ADD) {
+ color.rgb += light_color.rgb * light_color.a;
+ } else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_SUB) {
+ color.rgb -= light_color.rgb * light_color.a;
+ } else if (blend_mode == LIGHT_FLAGS_BLEND_MODE_MIX) {
+ color.rgb = mix(color.rgb, light_color.rgb, light_color.a);
}
}
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 27c292d163..a6db90c3f5 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1200,7 +1200,10 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f
vec3 spot_dir = spot_lights[idx].direction;
float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle));
- spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation);
+
+ mediump float cone_attenuation = spot_lights[idx].cone_attenuation;
+ spot_attenuation *= 1.0 - pow(spot_rim, cone_attenuation);
+
vec3 color = spot_lights[idx].color;
float size_A = 0.0;
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 5d01ab0346..1a41b60836 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -166,6 +166,11 @@ Config::Config() {
max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements");
max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights");
max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object");
+
+ //Adreno 3xx Compatibility
+ const String rendering_device_name = String::utf8((const char *)glGetString(GL_RENDERER));
+ //TODO: Check the number between 300 and 399(?)
+ adreno_3xx_compatibility = (rendering_device_name.left(13) == "Adreno (TM) 3");
}
Config::~Config() {
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index 1c0a5178bd..c3ab65f0bc 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -91,6 +91,8 @@ public:
bool rt_msaa_multiview_supported = false;
bool multiview_supported = false;
+ bool adreno_3xx_compatibility = false;
+
#ifdef ANDROID_ENABLED
PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC eglFramebufferTextureMultiviewOVR = nullptr;
PFNGLTEXSTORAGE3DMULTISAMPLEPROC eglTexStorage3DMultisample = nullptr;
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp
index f48e6eb7ed..21cf54b4be 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp
@@ -1113,12 +1113,12 @@ void RenderingDeviceDriverVulkan::_set_object_name(VkObjectType p_object_type, u
}
Error RenderingDeviceDriverVulkan::initialize(uint32_t p_device_index, uint32_t p_frame_count) {
- // Frame count is not required for the Vulkan driver, so we just ignore it.
-
context_device = context_driver->device_get(p_device_index);
physical_device = context_driver->physical_device_get(p_device_index);
vkGetPhysicalDeviceProperties(physical_device, &physical_device_properties);
+ frame_count = p_frame_count;
+
// Copy the queue family properties the context already retrieved.
uint32_t queue_family_count = context_driver->queue_family_get_count(p_device_index);
queue_family_properties.resize(queue_family_count);
@@ -2131,21 +2131,18 @@ RDD::CommandQueueID RenderingDeviceDriverVulkan::command_queue_create(CommandQue
return CommandQueueID(command_queue);
}
-Error RenderingDeviceDriverVulkan::command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) {
+Error RenderingDeviceDriverVulkan::command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) {
DEV_ASSERT(p_cmd_queue.id != 0);
+ VkResult err;
CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id);
Queue &device_queue = queue_families[command_queue->queue_family][command_queue->queue_index];
- Fence *fence = (Fence *)(p_signal_fence.id);
+ Fence *fence = (Fence *)(p_cmd_fence.id);
VkFence vk_fence = (fence != nullptr) ? fence->vk_fence : VK_NULL_HANDLE;
- thread_local LocalVector<VkCommandBuffer> command_buffers;
thread_local LocalVector<VkSemaphore> wait_semaphores;
- thread_local LocalVector<VkSemaphore> signal_semaphores;
thread_local LocalVector<VkPipelineStageFlags> wait_semaphores_stages;
- command_buffers.clear();
wait_semaphores.clear();
- signal_semaphores.clear();
wait_semaphores_stages.clear();
if (!command_queue->pending_semaphores_for_execute.is_empty()) {
@@ -2158,117 +2155,142 @@ Error RenderingDeviceDriverVulkan::command_queue_execute(CommandQueueID p_cmd_qu
command_queue->pending_semaphores_for_execute.clear();
}
- for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {
- command_buffers.push_back(VkCommandBuffer(p_cmd_buffers[i].id));
- }
-
for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) {
// FIXME: Allow specifying the stage mask in more detail.
wait_semaphores.push_back(VkSemaphore(p_wait_semaphores[i].id));
wait_semaphores_stages.push_back(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
}
- for (uint32_t i = 0; i < p_signal_semaphores.size(); i++) {
- signal_semaphores.push_back(VkSemaphore(p_signal_semaphores[i].id));
- }
-
- VkSubmitInfo submit_info = {};
- submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submit_info.waitSemaphoreCount = wait_semaphores.size();
- submit_info.pWaitSemaphores = wait_semaphores.ptr();
- submit_info.pWaitDstStageMask = wait_semaphores_stages.ptr();
- submit_info.commandBufferCount = command_buffers.size();
- submit_info.pCommandBuffers = command_buffers.ptr();
- submit_info.signalSemaphoreCount = signal_semaphores.size();
- submit_info.pSignalSemaphores = signal_semaphores.ptr();
+ if (p_cmd_buffers.size() > 0) {
+ thread_local LocalVector<VkCommandBuffer> command_buffers;
+ thread_local LocalVector<VkSemaphore> signal_semaphores;
+ command_buffers.clear();
+ signal_semaphores.clear();
- device_queue.submit_mutex.lock();
- VkResult err = vkQueueSubmit(device_queue.queue, 1, &submit_info, vk_fence);
- device_queue.submit_mutex.unlock();
- ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED);
-
- if (fence != nullptr && !command_queue->pending_semaphores_for_fence.is_empty()) {
- fence->queue_signaled_from = command_queue;
+ for (uint32_t i = 0; i < p_cmd_buffers.size(); i++) {
+ command_buffers.push_back(VkCommandBuffer(p_cmd_buffers[i].id));
+ }
- // Indicate to the fence that it should release the semaphores that were waited on this submission the next time the fence is waited on.
- for (uint32_t i = 0; i < command_queue->pending_semaphores_for_fence.size(); i++) {
- command_queue->image_semaphores_for_fences.push_back({ fence, command_queue->pending_semaphores_for_fence[i] });
+ for (uint32_t i = 0; i < p_cmd_semaphores.size(); i++) {
+ signal_semaphores.push_back(VkSemaphore(p_cmd_semaphores[i].id));
}
- command_queue->pending_semaphores_for_fence.clear();
- }
+ VkSemaphore present_semaphore = VK_NULL_HANDLE;
+ if (p_swap_chains.size() > 0) {
+ if (command_queue->present_semaphores.is_empty()) {
+ // Create the semaphores used for presentation if they haven't been created yet.
+ VkSemaphore semaphore = VK_NULL_HANDLE;
+ VkSemaphoreCreateInfo create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+
+ for (uint32_t i = 0; i < frame_count; i++) {
+ err = vkCreateSemaphore(vk_device, &create_info, nullptr, &semaphore);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED);
+ command_queue->present_semaphores.push_back(semaphore);
+ }
+ }
- return OK;
-}
+ // If a presentation semaphore is required, cycle across the ones available on the queue. It is technically possible
+ // and valid to reuse the same semaphore for this particular operation, but we create multiple ones anyway in case
+ // some hardware expects multiple semaphores to be used.
+ present_semaphore = command_queue->present_semaphores[command_queue->present_semaphore_index];
+ signal_semaphores.push_back(present_semaphore);
+ command_queue->present_semaphore_index = (command_queue->present_semaphore_index + 1) % command_queue->present_semaphores.size();
+ }
-Error RenderingDeviceDriverVulkan::command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) {
- DEV_ASSERT(p_cmd_queue.id != 0);
+ VkSubmitInfo submit_info = {};
+ submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
+ submit_info.waitSemaphoreCount = wait_semaphores.size();
+ submit_info.pWaitSemaphores = wait_semaphores.ptr();
+ submit_info.pWaitDstStageMask = wait_semaphores_stages.ptr();
+ submit_info.commandBufferCount = command_buffers.size();
+ submit_info.pCommandBuffers = command_buffers.ptr();
+ submit_info.signalSemaphoreCount = signal_semaphores.size();
+ submit_info.pSignalSemaphores = signal_semaphores.ptr();
+
+ device_queue.submit_mutex.lock();
+ err = vkQueueSubmit(device_queue.queue, 1, &submit_info, vk_fence);
+ device_queue.submit_mutex.unlock();
+ ERR_FAIL_COND_V(err != VK_SUCCESS, FAILED);
+
+ if (fence != nullptr && !command_queue->pending_semaphores_for_fence.is_empty()) {
+ fence->queue_signaled_from = command_queue;
+
+ // Indicate to the fence that it should release the semaphores that were waited on this submission the next time the fence is waited on.
+ for (uint32_t i = 0; i < command_queue->pending_semaphores_for_fence.size(); i++) {
+ command_queue->image_semaphores_for_fences.push_back({ fence, command_queue->pending_semaphores_for_fence[i] });
+ }
- CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id);
- Queue &device_queue = queue_families[command_queue->queue_family][command_queue->queue_index];
+ command_queue->pending_semaphores_for_fence.clear();
+ }
- thread_local LocalVector<VkSwapchainKHR> swapchains;
- thread_local LocalVector<uint32_t> image_indices;
- thread_local LocalVector<VkSemaphore> wait_semaphores;
- thread_local LocalVector<VkResult> results;
- swapchains.clear();
- image_indices.clear();
- for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
- SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
- swapchains.push_back(swap_chain->vk_swapchain);
- DEV_ASSERT(swap_chain->image_index < swap_chain->images.size());
- image_indices.push_back(swap_chain->image_index);
+ if (present_semaphore != VK_NULL_HANDLE) {
+ // If command buffers were executed, swap chains must wait on the present semaphore used by the command queue.
+ wait_semaphores.clear();
+ wait_semaphores.push_back(present_semaphore);
+ }
}
- wait_semaphores.clear();
- for (uint32_t i = 0; i < p_wait_semaphores.size(); i++) {
- wait_semaphores.push_back(VkSemaphore(p_wait_semaphores[i].id));
- }
+ if (p_swap_chains.size() > 0) {
+ thread_local LocalVector<VkSwapchainKHR> swapchains;
+ thread_local LocalVector<uint32_t> image_indices;
+ thread_local LocalVector<VkResult> results;
+ swapchains.clear();
+ image_indices.clear();
- results.resize(swapchains.size());
-
- VkPresentInfoKHR present_info = {};
- present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- present_info.waitSemaphoreCount = wait_semaphores.size();
- present_info.pWaitSemaphores = wait_semaphores.ptr();
- present_info.swapchainCount = swapchains.size();
- present_info.pSwapchains = swapchains.ptr();
- present_info.pImageIndices = image_indices.ptr();
- present_info.pResults = results.ptr();
- device_queue.submit_mutex.lock();
- VkResult err = device_functions.QueuePresentKHR(device_queue.queue, &present_info);
- device_queue.submit_mutex.unlock();
-
- // Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired.
- bool any_result_is_out_of_date = false;
- for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
- SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
- swap_chain->image_index = UINT_MAX;
- if (results[i] == VK_ERROR_OUT_OF_DATE_KHR) {
- context_driver->surface_set_needs_resize(swap_chain->surface, true);
- any_result_is_out_of_date = true;
+ for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
+ SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
+ swapchains.push_back(swap_chain->vk_swapchain);
+ DEV_ASSERT(swap_chain->image_index < swap_chain->images.size());
+ image_indices.push_back(swap_chain->image_index);
}
- }
- if (any_result_is_out_of_date || err == VK_ERROR_OUT_OF_DATE_KHR) {
- // It is possible for presentation to fail with out of date while acquire might've succeeded previously. This case
- // will be considered a silent failure as it can be triggered easily by resizing a window in the OS natively.
- return FAILED;
- }
+ results.resize(swapchains.size());
+
+ VkPresentInfoKHR present_info = {};
+ present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
+ present_info.waitSemaphoreCount = wait_semaphores.size();
+ present_info.pWaitSemaphores = wait_semaphores.ptr();
+ present_info.swapchainCount = swapchains.size();
+ present_info.pSwapchains = swapchains.ptr();
+ present_info.pImageIndices = image_indices.ptr();
+ present_info.pResults = results.ptr();
+
+ device_queue.submit_mutex.lock();
+ err = device_functions.QueuePresentKHR(device_queue.queue, &present_info);
+ device_queue.submit_mutex.unlock();
+
+ // Set the index to an invalid value. If any of the swap chains returned out of date, indicate it should be resized the next time it's acquired.
+ bool any_result_is_out_of_date = false;
+ for (uint32_t i = 0; i < p_swap_chains.size(); i++) {
+ SwapChain *swap_chain = (SwapChain *)(p_swap_chains[i].id);
+ swap_chain->image_index = UINT_MAX;
+ if (results[i] == VK_ERROR_OUT_OF_DATE_KHR) {
+ context_driver->surface_set_needs_resize(swap_chain->surface, true);
+ any_result_is_out_of_date = true;
+ }
+ }
- // Handling VK_SUBOPTIMAL_KHR the same as VK_SUCCESS is completely intentional.
- //
- // Godot does not currently support native rotation in Android when creating the swap chain. It intentionally uses
- // VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR instead of the current transform bits available in the surface capabilities.
- // Choosing the transform that leads to optimal presentation leads to distortion that makes the application unusable,
- // as the rotation of all the content is not handled at the moment.
- //
- // VK_SUBOPTIMAL_KHR is accepted as a successful case even if it's not the most efficient solution to work around this
- // problem. This behavior should not be changed unless the swap chain recreation uses the current transform bits, as
- // it'll lead to very low performance in Android by entering an endless loop where it'll always resize the swap chain
- // every frame.
+ if (any_result_is_out_of_date || err == VK_ERROR_OUT_OF_DATE_KHR) {
+ // It is possible for presentation to fail with out of date while acquire might've succeeded previously. This case
+ // will be considered a silent failure as it can be triggered easily by resizing a window in the OS natively.
+ return FAILED;
+ }
- ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, FAILED);
+ // Handling VK_SUBOPTIMAL_KHR the same as VK_SUCCESS is completely intentional.
+ //
+ // Godot does not currently support native rotation in Android when creating the swap chain. It intentionally uses
+ // VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR instead of the current transform bits available in the surface capabilities.
+ // Choosing the transform that leads to optimal presentation leads to distortion that makes the application unusable,
+ // as the rotation of all the content is not handled at the moment.
+ //
+ // VK_SUBOPTIMAL_KHR is accepted as a successful case even if it's not the most efficient solution to work around this
+ // problem. This behavior should not be changed unless the swap chain recreation uses the current transform bits, as
+ // it'll lead to very low performance in Android by entering an endless loop where it'll always resize the swap chain
+ // every frame.
+
+ ERR_FAIL_COND_V(err != VK_SUCCESS && err != VK_SUBOPTIMAL_KHR, FAILED);
+ }
return OK;
}
@@ -2278,6 +2300,11 @@ void RenderingDeviceDriverVulkan::command_queue_free(CommandQueueID p_cmd_queue)
CommandQueue *command_queue = (CommandQueue *)(p_cmd_queue.id);
+ // Erase all the semaphores used for presentation.
+ for (VkSemaphore semaphore : command_queue->present_semaphores) {
+ vkDestroySemaphore(vk_device, semaphore, nullptr);
+ }
+
// Erase all the semaphores used for image acquisition.
for (VkSemaphore semaphore : command_queue->image_semaphores) {
vkDestroySemaphore(vk_device, semaphore, nullptr);
diff --git a/drivers/vulkan/rendering_device_driver_vulkan.h b/drivers/vulkan/rendering_device_driver_vulkan.h
index 4abaeecd11..70c4cebba5 100644
--- a/drivers/vulkan/rendering_device_driver_vulkan.h
+++ b/drivers/vulkan/rendering_device_driver_vulkan.h
@@ -115,6 +115,7 @@ class RenderingDeviceDriverVulkan : public RenderingDeviceDriver {
VkDevice vk_device = VK_NULL_HANDLE;
RenderingContextDriverVulkan *context_driver = nullptr;
RenderingContextDriver::Device context_device = {};
+ uint32_t frame_count = 1;
VkPhysicalDevice physical_device = VK_NULL_HANDLE;
VkPhysicalDeviceProperties physical_device_properties = {};
VkPhysicalDeviceFeatures physical_device_features = {};
@@ -276,6 +277,7 @@ public:
// ----- QUEUE -----
private:
struct CommandQueue {
+ LocalVector<VkSemaphore> present_semaphores;
LocalVector<VkSemaphore> image_semaphores;
LocalVector<SwapChain *> image_semaphores_swap_chains;
LocalVector<uint32_t> pending_semaphores_for_execute;
@@ -284,12 +286,12 @@ private:
LocalVector<Pair<Fence *, uint32_t>> image_semaphores_for_fences;
uint32_t queue_family = 0;
uint32_t queue_index = 0;
+ uint32_t present_semaphore_index = 0;
};
public:
virtual CommandQueueID command_queue_create(CommandQueueFamilyID p_cmd_queue_family, bool p_identify_as_main_queue = false) override final;
- virtual Error command_queue_execute(CommandQueueID p_cmd_queue, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_wait_semaphores, VectorView<SemaphoreID> p_signal_semaphores, FenceID p_signal_fence) override final;
- virtual Error command_queue_present(CommandQueueID p_cmd_queue, VectorView<SwapChainID> p_swap_chains, VectorView<SemaphoreID> p_wait_semaphores) override final;
+ virtual Error command_queue_execute_and_present(CommandQueueID p_cmd_queue, VectorView<SemaphoreID> p_wait_semaphores, VectorView<CommandBufferID> p_cmd_buffers, VectorView<SemaphoreID> p_cmd_semaphores, FenceID p_cmd_fence, VectorView<SwapChainID> p_swap_chains) override final;
virtual void command_queue_free(CommandQueueID p_cmd_queue) override final;
private: