Skip to content

Commit

Permalink
Skip swapchain logic if there is nothing to present (Android OpenXR)
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Oct 31, 2023
1 parent 93cdacb commit d780436
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 131 deletions.
14 changes: 6 additions & 8 deletions drivers/gles3/rasterizer_gles3.cpp
Expand Up @@ -103,6 +103,11 @@ void RasterizerGLES3::begin_frame(double frame_step) {
}

void RasterizerGLES3::end_frame(bool p_swap_buffers) {
GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
utils->capture_timestamps_end();
}

void RasterizerGLES3::end_viewport(bool p_swap_buffers) {
if (p_swap_buffers) {
DisplayServer::get_singleton()->swap_buffers();
} else {
Expand Down Expand Up @@ -352,13 +357,6 @@ RasterizerGLES3::~RasterizerGLES3() {
}

void RasterizerGLES3::prepare_for_blitting_render_targets() {
// This is a hack, but this function is called one time after all viewports have been updated.
// So it marks the end of the frame for all viewports
// In the OpenGL renderer we have to call end_frame for each viewport so we can swap the
// buffers for each window before proceeding to the next.
// This allows us to only increment the frame after all viewports are done.
GLES3::Utilities *utils = GLES3::Utilities::get_singleton();
utils->capture_timestamps_end();
}

void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first) {
Expand Down Expand Up @@ -474,7 +472,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
copy_effects->copy_to_rect(screenrect);
glBindTexture(GL_TEXTURE_2D, 0);

end_frame(true);
end_viewport(true);

texture_storage->texture_free(texture);
}
Expand Down
1 change: 1 addition & 0 deletions drivers/gles3/rasterizer_gles3.h
Expand Up @@ -93,6 +93,7 @@ class RasterizerGLES3 : public RendererCompositor {
void prepare_for_blitting_render_targets();
void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);

void end_viewport(bool p_swap_buffers);
void end_frame(bool p_swap_buffers);

void finalize();
Expand Down
4 changes: 2 additions & 2 deletions drivers/vulkan/rendering_device_vulkan.cpp
Expand Up @@ -8751,9 +8751,9 @@ void RenderingDeviceVulkan::swap_buffers() {

_finalize_command_bufers();

screen_prepared = false;
// Swap buffers.
context->swap_buffers();
context->swap_buffers(screen_prepared);
screen_prepared = false;

frame = (frame + 1) % frame_count;

Expand Down
226 changes: 114 additions & 112 deletions drivers/vulkan/vulkan_context.cpp
Expand Up @@ -2468,7 +2468,7 @@ Error VulkanContext::prepare_buffers() {
return OK;
}

Error VulkanContext::swap_buffers() {
Error VulkanContext::swap_buffers(bool p_present) {
if (!queues_initialized) {
return OK;
}
Expand Down Expand Up @@ -2538,134 +2538,136 @@ Error VulkanContext::swap_buffers() {
command_buffer_queue.write[0] = nullptr;
command_buffer_count = 1;

if (separate_present_queue) {
// If we are using separate queues, change image ownership to the
// present queue before presenting, waiting for the draw complete
// semaphore and signaling the ownership released semaphore when finished.
VkFence nullFence = VK_NULL_HANDLE;
pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index];
submit_info.commandBufferCount = 0;

VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size());
submit_info.pCommandBuffers = cmdbufptr;

for (KeyValue<int, Window> &E : windows) {
Window *w = &E.value;

if (w->swapchain == VK_NULL_HANDLE) {
continue;
if (p_present) {
if (separate_present_queue) {
// If we are using separate queues, change image ownership to the
// present queue before presenting, waiting for the draw complete
// semaphore and signaling the ownership released semaphore when finished.
VkFence nullFence = VK_NULL_HANDLE;
pipe_stage_flags[0] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
submit_info.waitSemaphoreCount = 1;
submit_info.pWaitSemaphores = &draw_complete_semaphores[frame_index];
submit_info.commandBufferCount = 0;

VkCommandBuffer *cmdbufptr = (VkCommandBuffer *)alloca(sizeof(VkCommandBuffer *) * windows.size());
submit_info.pCommandBuffers = cmdbufptr;

for (KeyValue<int, Window> &E : windows) {
Window *w = &E.value;

if (w->swapchain == VK_NULL_HANDLE) {
continue;
}
cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd;
submit_info.commandBufferCount++;
}
cmdbufptr[submit_info.commandBufferCount] = w->swapchain_image_resources[w->current_buffer].graphics_to_present_cmd;
submit_info.commandBufferCount++;
}

submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index];
err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence);
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit present queue. Error code: " + String(string_VkResult(err)));
}
submit_info.signalSemaphoreCount = 1;
submit_info.pSignalSemaphores = &image_ownership_semaphores[frame_index];
err = vkQueueSubmit(present_queue, 1, &submit_info, nullFence);
ERR_FAIL_COND_V_MSG(err, ERR_CANT_CREATE, "Vulkan: Cannot submit present queue. Error code: " + String(string_VkResult(err)));
}

// If we are using separate queues, we have to wait for image ownership,
// otherwise wait for draw complete.
VkPresentInfoKHR present = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
/*pNext*/ nullptr,
/*waitSemaphoreCount*/ 1,
/*pWaitSemaphores*/ (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index],
/*swapchainCount*/ 0,
/*pSwapchain*/ nullptr,
/*pImageIndices*/ nullptr,
/*pResults*/ nullptr,
};
// If we are using separate queues, we have to wait for image ownership,
// otherwise wait for draw complete.
VkPresentInfoKHR present = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
/*pNext*/ nullptr,
/*waitSemaphoreCount*/ 1,
/*pWaitSemaphores*/ (separate_present_queue) ? &image_ownership_semaphores[frame_index] : &draw_complete_semaphores[frame_index],
/*swapchainCount*/ 0,
/*pSwapchain*/ nullptr,
/*pImageIndices*/ nullptr,
/*pResults*/ nullptr,
};

VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size());
uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size());
VkSwapchainKHR *pSwapchains = (VkSwapchainKHR *)alloca(sizeof(VkSwapchainKHR *) * windows.size());
uint32_t *pImageIndices = (uint32_t *)alloca(sizeof(uint32_t *) * windows.size());

present.pSwapchains = pSwapchains;
present.pImageIndices = pImageIndices;
present.pSwapchains = pSwapchains;
present.pImageIndices = pImageIndices;

for (KeyValue<int, Window> &E : windows) {
Window *w = &E.value;
for (KeyValue<int, Window> &E : windows) {
Window *w = &E.value;

if (w->swapchain == VK_NULL_HANDLE) {
continue;
if (w->swapchain == VK_NULL_HANDLE) {
continue;
}
pSwapchains[present.swapchainCount] = w->swapchain;
pImageIndices[present.swapchainCount] = w->current_buffer;
present.swapchainCount++;
}
pSwapchains[present.swapchainCount] = w->swapchain;
pImageIndices[present.swapchainCount] = w->current_buffer;
present.swapchainCount++;
}

#if 0
if (is_device_extension_enabled(VK_KHR_incremental_present_enabled)) {
// If using VK_KHR_incremental_present, we provide a hint of the region
// that contains changed content relative to the previously-presented
// image. The implementation can use this hint in order to save
// work/power (by only copying the region in the hint). The
// implementation is free to ignore the hint though, and so we must
// ensure that the entire image has the correctly-drawn content.
uint32_t eighthOfWidth = width / 8;
uint32_t eighthOfHeight = height / 8;
VkRectLayerKHR rect = {
/*offset.x*/ eighthOfWidth,
/*offset.y*/ eighthOfHeight,
/*extent.width*/ eighthOfWidth * 6,
/*extent.height*/ eighthOfHeight * 6,
/*layer*/ 0,
};
VkPresentRegionKHR region = {
/*rectangleCount*/ 1,
/*pRectangles*/ &rect,
};
VkPresentRegionsKHR regions = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
/*pNext*/ present.pNext,
/*swapchainCount*/ present.swapchainCount,
/*pRegions*/ &region,
};
present.pNext = &regions;
}
if (is_device_extension_enabled(VK_KHR_incremental_present_enabled)) {
// If using VK_KHR_incremental_present, we provide a hint of the region
// that contains changed content relative to the previously-presented
// image. The implementation can use this hint in order to save
// work/power (by only copying the region in the hint). The
// implementation is free to ignore the hint though, and so we must
// ensure that the entire image has the correctly-drawn content.
uint32_t eighthOfWidth = width / 8;
uint32_t eighthOfHeight = height / 8;
VkRectLayerKHR rect = {
/*offset.x*/ eighthOfWidth,
/*offset.y*/ eighthOfHeight,
/*extent.width*/ eighthOfWidth * 6,
/*extent.height*/ eighthOfHeight * 6,
/*layer*/ 0,
};
VkPresentRegionKHR region = {
/*rectangleCount*/ 1,
/*pRectangles*/ &rect,
};
VkPresentRegionsKHR regions = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR,
/*pNext*/ present.pNext,
/*swapchainCount*/ present.swapchainCount,
/*pRegions*/ &region,
};
present.pNext = &regions;
}
#endif

#if 0
if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
VkPresentTimeGOOGLE ptime;
if (prev_desired_present_time == 0) {
// This must be the first present for this swapchain.
//
// We don't know where we are relative to the presentation engine's
// display's refresh cycle. We also don't know how long rendering
// takes. Let's make a grossly-simplified assumption that the
// desiredPresentTime should be half way between now and
// now+target_IPD. We will adjust over time.
uint64_t curtime = getTimeInNanoseconds();
if (curtime == 0) {
// Since we didn't find out the current time, don't give a
// desiredPresentTime.
ptime.desiredPresentTime = 0;
if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
VkPresentTimeGOOGLE ptime;
if (prev_desired_present_time == 0) {
// This must be the first present for this swapchain.
//
// We don't know where we are relative to the presentation engine's
// display's refresh cycle. We also don't know how long rendering
// takes. Let's make a grossly-simplified assumption that the
// desiredPresentTime should be half way between now and
// now+target_IPD. We will adjust over time.
uint64_t curtime = getTimeInNanoseconds();
if (curtime == 0) {
// Since we didn't find out the current time, don't give a
// desiredPresentTime.
ptime.desiredPresentTime = 0;
} else {
ptime.desiredPresentTime = curtime + (target_IPD >> 1);
}
} else {
ptime.desiredPresentTime = curtime + (target_IPD >> 1);
ptime.desiredPresentTime = (prev_desired_present_time + target_IPD);
}
ptime.presentID = next_present_id++;
prev_desired_present_time = ptime.desiredPresentTime;

VkPresentTimesInfoGOOGLE present_time = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
/*pNext*/ present.pNext,
/*swapchainCount*/ present.swapchainCount,
/*pTimes*/ &ptime,
};
if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
present.pNext = &present_time;
}
} else {
ptime.desiredPresentTime = (prev_desired_present_time + target_IPD);
}
ptime.presentID = next_present_id++;
prev_desired_present_time = ptime.desiredPresentTime;

VkPresentTimesInfoGOOGLE present_time = {
/*sType*/ VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE,
/*pNext*/ present.pNext,
/*swapchainCount*/ present.swapchainCount,
/*pTimes*/ &ptime,
};
if (is_device_extension_enabled(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME)) {
present.pNext = &present_time;
}
}
#endif
// print_line("current buffer: " + itos(current_buffer));
err = fpQueuePresentKHR(present_queue, &present);
// print_line("current buffer: " + itos(current_buffer));
err = fpQueuePresentKHR(present_queue, &present);
}

frame_index += 1;
frame_index %= FRAME_LAG;
Expand Down
2 changes: 1 addition & 1 deletion drivers/vulkan/vulkan_context.h
Expand Up @@ -328,7 +328,7 @@ class VulkanContext {
void resize_notify();
void flush(bool p_flush_setup = false, bool p_flush_pending = false);
Error prepare_buffers();
Error swap_buffers();
Error swap_buffers(bool p_present);
Error initialize();

void command_begin_label(VkCommandBuffer p_command_buffer, String p_label_name, const Color p_color);
Expand Down
2 changes: 2 additions & 0 deletions servers/rendering/dummy/rasterizer_dummy.h
Expand Up @@ -89,6 +89,8 @@ class RasterizerDummy : public RendererCompositor {
void prepare_for_blitting_render_targets() override {}
void blit_render_targets_to_screen(int p_screen, const BlitToScreen *p_render_targets, int p_amount) override {}

void end_viewport(bool p_swap_buffers) override {}

void end_frame(bool p_swap_buffers) override {
if (p_swap_buffers) {
DisplayServer::get_singleton()->swap_buffers();
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/renderer_compositor.h
Expand Up @@ -99,6 +99,7 @@ class RendererCompositor {
virtual void prepare_for_blitting_render_targets() = 0;
virtual void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) = 0;

virtual void end_viewport(bool p_swap_buffers) = 0;
virtual void end_frame(bool p_swap_buffers) = 0;
virtual void finalize() = 0;
virtual uint64_t get_frame_number() const = 0;
Expand Down
1 change: 1 addition & 0 deletions servers/rendering/renderer_rd/renderer_compositor_rd.h
Expand Up @@ -123,6 +123,7 @@ class RendererCompositorRD : public RendererCompositor {
void prepare_for_blitting_render_targets();
void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount);

void end_viewport(bool p_swap_buffers) {}
void end_frame(bool p_swap_buffers);
void finalize();

Expand Down
8 changes: 4 additions & 4 deletions servers/rendering/renderer_viewport.cpp
Expand Up @@ -749,7 +749,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
if (blits.size() > 0) {
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
}
RSG::rasterizer->end_frame(true);
} else if (blits.size() > 0) {
if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
Expand All @@ -759,6 +758,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
}
}
RSG::rasterizer->end_viewport(p_swap_buffers && blits.size() > 0);
}
}
} else {
Expand Down Expand Up @@ -788,10 +788,10 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
Vector<BlitToScreen> blit_to_screen_vec;
blit_to_screen_vec.push_back(blit);
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blit_to_screen_vec.ptr(), 1);
RSG::rasterizer->end_frame(true);
} else {
blit_to_screen_list[vp->viewport_to_screen].push_back(blit);
}
RSG::rasterizer->end_viewport(p_swap_buffers);
}
}

Expand All @@ -813,8 +813,8 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {

RENDER_TIMESTAMP("< Render Viewports");

if (p_swap_buffers) {
//this needs to be called to make screen swapping more efficient
if (p_swap_buffers && !blit_to_screen_list.is_empty()) {
// This needs to be called to make screen swapping more efficient.
RSG::rasterizer->prepare_for_blitting_render_targets();

for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) {
Expand Down
5 changes: 1 addition & 4 deletions servers/rendering/rendering_server_default.cpp
Expand Up @@ -91,10 +91,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::viewport->draw_viewports(p_swap_buffers);
RSG::canvas_render->update();

if (!OS::get_singleton()->get_current_rendering_driver_name().begins_with("opengl3")) {
// Already called for gl_compatibility renderer.
RSG::rasterizer->end_frame(p_swap_buffers);
}
RSG::rasterizer->end_frame(p_swap_buffers);

XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
Expand Down

0 comments on commit d780436

Please sign in to comment.