diff --git a/libobs-d3d11/d3d11-subsystem.cpp b/libobs-d3d11/d3d11-subsystem.cpp index 8fad75087..2a0f0b20f 100644 --- a/libobs-d3d11/d3d11-subsystem.cpp +++ b/libobs-d3d11/d3d11-subsystem.cpp @@ -274,16 +274,6 @@ gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data) effect = DXGI_SWAP_EFFECT_FLIP_DISCARD; flags |= DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT; - - BOOL featureSupportData = FALSE; - const HRESULT hr = factory5->CheckFeatureSupport( - DXGI_FEATURE_PRESENT_ALLOW_TEARING, &featureSupportData, - sizeof(featureSupportData)); - if (SUCCEEDED(hr) && featureSupportData) { - presentFlags |= DXGI_PRESENT_ALLOW_TEARING; - - flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; - } } space = make_swap_desc(device, swapDesc, &initData, effect, flags); @@ -298,11 +288,9 @@ gs_swap_chain::gs_swap_chain(gs_device *device, const gs_init_data *data) if (flags & DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT) { ComPtr swap2 = ComQIPtr(swap); hWaitable = swap2->GetFrameLatencyWaitableObject(); - if (hWaitable) { - hr = swap2->SetMaximumFrameLatency(40); - if (FAILED(hr)) - throw HRError("Could not relax frame latency", - hr); + if (hWaitable == NULL) { + throw HRError("Failed to GetFrameLatencyWaitableObject", + hr); } } @@ -2348,20 +2336,31 @@ void device_clear(gs_device_t *device, uint32_t clear_flags, } } +bool device_is_present_ready(gs_device_t *device) +{ + gs_swap_chain *const curSwapChain = device->curSwapChain; + bool ready = curSwapChain != nullptr; + if (ready) { + const HANDLE hWaitable = curSwapChain->hWaitable; + ready = (hWaitable == NULL) || + WaitForSingleObject(hWaitable, 0) == WAIT_OBJECT_0; + } else { + blog(LOG_WARNING, + "device_is_present_ready (D3D11): No active swap"); + } + + return ready; +} + void device_present(gs_device_t *device) { gs_swap_chain *const curSwapChain = device->curSwapChain; if (curSwapChain) { - /* Skip Present at frame limit to avoid stall */ - const HANDLE hWaitable = curSwapChain->hWaitable; - if ((hWaitable == NULL) || - WaitForSingleObject(hWaitable, 0) == WAIT_OBJECT_0) { - const HRESULT hr = curSwapChain->swap->Present( - 0, curSwapChain->presentFlags); - if (hr == DXGI_ERROR_DEVICE_REMOVED || - hr == DXGI_ERROR_DEVICE_RESET) { - device->RebuildDevice(); - } + const UINT interval = curSwapChain->hWaitable ? 1 : 0; + const HRESULT hr = curSwapChain->swap->Present(interval, 0); + if (hr == DXGI_ERROR_DEVICE_REMOVED || + hr == DXGI_ERROR_DEVICE_RESET) { + device->RebuildDevice(); } } else { blog(LOG_WARNING, "device_present (D3D11): No active swap"); diff --git a/libobs-d3d11/d3d11-subsystem.hpp b/libobs-d3d11/d3d11-subsystem.hpp index 6ffc5fcb8..0d4ff24a2 100644 --- a/libobs-d3d11/d3d11-subsystem.hpp +++ b/libobs-d3d11/d3d11-subsystem.hpp @@ -821,7 +821,6 @@ struct gs_swap_chain : gs_obj { gs_init_data initData; DXGI_SWAP_CHAIN_DESC swapDesc = {}; gs_color_space space; - UINT presentFlags = 0; gs_texture_2d target; gs_zstencil_buffer zs; diff --git a/libobs-opengl/gl-cocoa.m b/libobs-opengl/gl-cocoa.m index c4a69d08c..bdd8d54e1 100644 --- a/libobs-opengl/gl-cocoa.m +++ b/libobs-opengl/gl-cocoa.m @@ -287,6 +287,12 @@ void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap) } } +bool device_is_present_ready(gs_device_t *device) +{ + UNUSED_PARAMETER(device); + return true; +} + void device_present(gs_device_t *device) { glFlush(); diff --git a/libobs-opengl/gl-nix.c b/libobs-opengl/gl-nix.c index 68a412cf8..52a300346 100644 --- a/libobs-opengl/gl-nix.c +++ b/libobs-opengl/gl-nix.c @@ -115,6 +115,12 @@ extern void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap) gl_vtable->device_load_swapchain(device, swap); } +extern bool device_is_present_ready(gs_device_t *device) +{ + UNUSED_PARAMETER(device); + return true; +} + extern void device_present(gs_device_t *device) { gl_vtable->device_present(device); diff --git a/libobs-opengl/gl-windows.c b/libobs-opengl/gl-windows.c index d9fcd28a2..e9f3f0938 100644 --- a/libobs-opengl/gl-windows.c +++ b/libobs-opengl/gl-windows.c @@ -573,6 +573,12 @@ void device_load_swapchain(gs_device_t *device, gs_swapchain_t *swap) } } +bool device_is_present_ready(gs_device_t *device) +{ + UNUSED_PARAMETER(device); + return true; +} + void device_present(gs_device_t *device) { if (!SwapBuffers(device->cur_swap->wi->hdc)) { diff --git a/libobs/graphics/device-exports.h b/libobs/graphics/device-exports.h index 290d33f94..6200796ed 100644 --- a/libobs/graphics/device-exports.h +++ b/libobs/graphics/device-exports.h @@ -133,6 +133,7 @@ EXPORT void device_load_swapchain(gs_device_t *device, EXPORT void device_clear(gs_device_t *device, uint32_t clear_flags, const struct vec4 *color, float depth, uint8_t stencil); +EXPORT bool device_is_present_ready(gs_device_t *device); EXPORT void device_present(gs_device_t *device); EXPORT void device_flush(gs_device_t *device); EXPORT void device_set_cull_mode(gs_device_t *device, enum gs_cull_mode mode); diff --git a/libobs/graphics/graphics-imports.c b/libobs/graphics/graphics-imports.c index 4a7e31d9b..b7a32890e 100644 --- a/libobs/graphics/graphics-imports.c +++ b/libobs/graphics/graphics-imports.c @@ -96,6 +96,7 @@ bool load_graphics_imports(struct gs_exports *exports, void *module, GRAPHICS_IMPORT(device_load_swapchain); GRAPHICS_IMPORT(device_end_scene); GRAPHICS_IMPORT(device_clear); + GRAPHICS_IMPORT(device_is_present_ready); GRAPHICS_IMPORT(device_present); GRAPHICS_IMPORT(device_flush); GRAPHICS_IMPORT(device_set_cull_mode); diff --git a/libobs/graphics/graphics-internal.h b/libobs/graphics/graphics-internal.h index fb2a75e3c..434b76187 100644 --- a/libobs/graphics/graphics-internal.h +++ b/libobs/graphics/graphics-internal.h @@ -133,6 +133,7 @@ struct gs_exports { void (*device_clear)(gs_device_t *device, uint32_t clear_flags, const struct vec4 *color, float depth, uint8_t stencil); + bool (*device_is_present_ready)(gs_device_t *device); void (*device_present)(gs_device_t *device); void (*device_flush)(gs_device_t *device); void (*device_set_cull_mode)(gs_device_t *device, diff --git a/libobs/graphics/graphics.c b/libobs/graphics/graphics.c index 66365e1bf..c68b26afc 100644 --- a/libobs/graphics/graphics.c +++ b/libobs/graphics/graphics.c @@ -1943,6 +1943,16 @@ void gs_clear(uint32_t clear_flags, const struct vec4 *color, float depth, depth, stencil); } +bool gs_is_present_ready(void) +{ + graphics_t *graphics = thread_graphics; + + if (!gs_valid("gs_is_present_ready")) + return false; + + return graphics->exports.device_is_present_ready(graphics->device); +} + void gs_present(void) { graphics_t *graphics = thread_graphics; diff --git a/libobs/graphics/graphics.h b/libobs/graphics/graphics.h index fa9f9e55b..b18f5d9bb 100644 --- a/libobs/graphics/graphics.h +++ b/libobs/graphics/graphics.h @@ -742,6 +742,7 @@ EXPORT void gs_end_scene(void); EXPORT void gs_load_swapchain(gs_swapchain_t *swapchain); EXPORT void gs_clear(uint32_t clear_flags, const struct vec4 *color, float depth, uint8_t stencil); +EXPORT bool gs_is_present_ready(void); EXPORT void gs_present(void); EXPORT void gs_flush(void); diff --git a/libobs/obs-display.c b/libobs/obs-display.c index 9f12a2b47..75ed1ecbe 100644 --- a/libobs/obs-display.c +++ b/libobs/obs-display.c @@ -166,7 +166,7 @@ void obs_display_remove_draw_callback(obs_display_t *display, pthread_mutex_unlock(&display->draw_callbacks_mutex); } -static inline void render_display_begin(struct obs_display *display, +static inline bool render_display_begin(struct obs_display *display, uint32_t cx, uint32_t cy, bool update_color_space) { @@ -182,23 +182,29 @@ static inline void render_display_begin(struct obs_display *display, gs_update_color_space(); } - gs_begin_scene(); + const bool success = gs_is_present_ready(); + if (success) { + gs_begin_scene(); - if (gs_get_color_space() == GS_CS_SRGB) - vec4_from_rgba(&clear_color, display->background_color); - else - vec4_from_rgba_srgb(&clear_color, display->background_color); - clear_color.w = 1.0f; + if (gs_get_color_space() == GS_CS_SRGB) + vec4_from_rgba(&clear_color, display->background_color); + else + vec4_from_rgba_srgb(&clear_color, + display->background_color); + clear_color.w = 1.0f; - gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH | GS_CLEAR_STENCIL, - &clear_color, 1.0f, 0); + gs_clear(GS_CLEAR_COLOR | GS_CLEAR_DEPTH | GS_CLEAR_STENCIL, + &clear_color, 1.0f, 0); - gs_enable_depth_test(false); - /* gs_enable_blending(false); */ - gs_set_cull_mode(GS_NEITHER); + gs_enable_depth_test(false); + /* gs_enable_blending(false); */ + gs_set_cull_mode(GS_NEITHER); - gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f); - gs_set_viewport(0, 0, cx, cy); + gs_ortho(0.0f, (float)cx, 0.0f, (float)cy, -100.0f, 100.0f); + gs_set_viewport(0, 0, cx, cy); + } + + return success; } static inline void render_display_end() @@ -230,24 +236,24 @@ void render_display(struct obs_display *display) /* -------------------------------------------- */ - render_display_begin(display, cx, cy, update_color_space); + if (render_display_begin(display, cx, cy, update_color_space)) { + pthread_mutex_lock(&display->draw_callbacks_mutex); - pthread_mutex_lock(&display->draw_callbacks_mutex); + for (size_t i = 0; i < display->draw_callbacks.num; i++) { + struct draw_callback *callback; + callback = display->draw_callbacks.array + i; - for (size_t i = 0; i < display->draw_callbacks.num; i++) { - struct draw_callback *callback; - callback = display->draw_callbacks.array + i; + callback->draw(callback->param, cx, cy); + } - callback->draw(callback->param, cx, cy); + pthread_mutex_unlock(&display->draw_callbacks_mutex); + + render_display_end(); + + GS_DEBUG_MARKER_END(); + + gs_present(); } - - pthread_mutex_unlock(&display->draw_callbacks_mutex); - - render_display_end(); - - GS_DEBUG_MARKER_END(); - - gs_present(); } void obs_display_set_enabled(obs_display_t *display, bool enable)