From db2ee08e2c92f98ea39c7a995654331927b79bbf Mon Sep 17 00:00:00 2001 From: David Steele Date: Wed, 7 Feb 2024 11:46:13 +0000 Subject: [PATCH] [Tizen] Changed FBOs to use EglSync For texture dependencies between shared context and render surface context (i.e. Window/Scene surface), e.g. when an offscreen is rendered on-screen, have changed to use EglClientWaitSync with timeout = FOREVER. This blocks the CPU when sending draw calls to the GPU where that draw call uses an offscreen texture. However, in testing gaussian-blur-view.example, this lasts approx 10ms on some frames and 16/17 ms on others, yielding an FPS of 41. Changed egl-sync-implementation.cpp to have multiple versions of the file for each platform, rather than old-style #ifdefs. (Todo: could check if the offscreen was re-rendered this frame, as there is no need to sync if it hasn't changed. But, client can use RENDER_ONCE to force this behaviour). + Fixed some SVACE errors Change-Id: I64eaf82c5203e6acb6e0fc76b0f0e36136defcdf --- .../test-graphics-sync-impl.cpp | 10 ++ .../test-graphics-sync-impl.h | 7 +- .../test-graphics-sync-object.h | 5 +- .../android/egl-sync-implementation-android.cpp | 96 ++++++++++++++ dali/internal/graphics/common/egl-include.h | 3 + dali/internal/graphics/file.list | 7 +- .../graphics/generic/egl-sync-implementation.cpp | 143 +++++++++++++++++++++ .../graphics/gles-impl/egl-sync-object.cpp | 2 +- dali/internal/graphics/gles-impl/egl-sync-object.h | 6 +- dali/internal/graphics/gles-impl/gles-context.cpp | 4 +- .../graphics/gles-impl/gles-sync-object.cpp | 2 +- .../internal/graphics/gles-impl/gles-sync-object.h | 5 +- .../internal/graphics/gles-impl/gles-sync-pool.cpp | 116 ++++++++++++++--- dali/internal/graphics/gles-impl/gles-sync-pool.h | 51 ++++++-- .../gles-impl/gles-texture-dependency-checker.cpp | 35 +++-- .../gles-impl/gles-texture-dependency-checker.h | 17 ++- .../graphics/gles/egl-sync-implementation.h | 17 ++- .../macos/egl-sync-implementation-macos.cpp | 96 ++++++++++++++ .../egl-sync-implementation-tizen.cpp} | 76 +++++++++-- .../windows-gl/egl-sync-implementation-windows.cpp | 96 ++++++++++++++ 20 files changed, 732 insertions(+), 62 deletions(-) create mode 100644 dali/internal/graphics/android/egl-sync-implementation-android.cpp create mode 100644 dali/internal/graphics/generic/egl-sync-implementation.cpp create mode 100644 dali/internal/graphics/macos/egl-sync-implementation-macos.cpp rename dali/internal/graphics/{gles/egl-sync-implementation.cpp => tizen/egl-sync-implementation-tizen.cpp} (70%) create mode 100644 dali/internal/graphics/windows-gl/egl-sync-implementation-windows.cpp diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.cpp index 17f53a7..bb4a500 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.cpp +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.cpp @@ -38,6 +38,16 @@ bool TestSyncObject::IsSynced() return synced; } +void TestSyncObject::Wait() +{ + mTrace.PushCall("SyncObject::Wait", ""); // Trace the method +} + +void TestSyncObject::ClientWait() +{ + mTrace.PushCall("SyncObject::ClientWait", ""); // Trace the method +} + TestGraphicsSyncImplementation::TestGraphicsSyncImplementation() { Initialize(); diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.h index cbc5331..21fd358 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-impl.h @@ -2,7 +2,7 @@ #define TEST_SYNC_IMPLEMENTATION_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,7 +40,10 @@ class TestSyncObject : public Integration::GraphicsSyncAbstraction::SyncObject public: TestSyncObject(TraceCallStack& trace); ~TestSyncObject() override; - bool IsSynced() override; + bool IsSynced() override; + void Wait() override; + void ClientWait() override; + bool synced; TraceCallStack& mTrace; }; diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-object.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-object.h index c33de6c..6886687 100644 --- a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-object.h +++ b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-graphics-sync-object.h @@ -2,7 +2,7 @@ #define DALI_TEST_GRAPHICS_SYNC_OBJECT_H_ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,8 +19,7 @@ #include #include - -#include +#include "test-graphics-sync-impl.h" namespace Dali { diff --git a/dali/internal/graphics/android/egl-sync-implementation-android.cpp b/dali/internal/graphics/android/egl-sync-implementation-android.cpp new file mode 100644 index 0000000..df12970 --- /dev/null +++ b/dali/internal/graphics/android/egl-sync-implementation-android.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES + +#include + +// INTERNAL INCLUDES +#include +#include + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogSyncFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FENCE_SYNC"); +#endif + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +EglSyncObject::EglSyncObject(EglImplementation& eglImpl) +: mPollCounter(3), + mEglImplementation(eglImpl) +{ +} + +EglSyncObject::~EglSyncObject() +{ +} + +bool EglSyncObject::IsSynced() +{ + return true; +} + +void EglSyncObject::Wait() +{ +} + +void EglSyncObject::ClientWait() +{ +} + +EglSyncImplementation::EglSyncImplementation() +: mEglImplementation(NULL), + mSyncInitialized(false), + mSyncInitializeFailed(false) +{ +} + +EglSyncImplementation::~EglSyncImplementation() +{ +} + +void EglSyncImplementation::Initialize(EglImplementation* eglImpl) +{ + mEglImplementation = eglImpl; +} + +Integration::GraphicsSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject() +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + return new EglSyncObject(*mEglImplementation); +} + +void EglSyncImplementation::DestroySyncObject(Integration::GraphicsSyncAbstraction::SyncObject* syncObject) +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + delete static_cast(syncObject); +} + +void EglSyncImplementation::InitializeEglSync() +{ +} + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali diff --git a/dali/internal/graphics/common/egl-include.h b/dali/internal/graphics/common/egl-include.h index 96ce884..905291c 100644 --- a/dali/internal/graphics/common/egl-include.h +++ b/dali/internal/graphics/common/egl-include.h @@ -5,6 +5,8 @@ #include // Undef unneded symbols that fail to compile on MS Windows +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) /* Win32 and WinCE */ + #undef ERROR #undef OPAQUE @@ -20,6 +22,7 @@ #undef max #undef DIFFERENCE +#endif #include diff --git a/dali/internal/graphics/file.list b/dali/internal/graphics/file.list index 8041345..3f8b5dd 100644 --- a/dali/internal/graphics/file.list +++ b/dali/internal/graphics/file.list @@ -3,7 +3,6 @@ SET( adaptor_graphics_gles_src_files ${adaptor_graphics_dir}/gles/egl-debug.cpp ${adaptor_graphics_dir}/gles/egl-implementation.cpp - ${adaptor_graphics_dir}/gles/egl-sync-implementation.cpp ${adaptor_graphics_dir}/gles/gl-extensions.cpp ${adaptor_graphics_dir}/gles/gl-extensions-support.cpp ${adaptor_graphics_dir}/gles/gl-implementation.cpp @@ -17,31 +16,37 @@ INCLUDE( ${adaptor_graphics_dir}/gles-impl/file.list ) # module: graphics, backend: tizen SET( adaptor_graphics_tizen_src_files ${adaptor_graphics_dir}/tizen/egl-image-extensions-tizen.cpp + ${adaptor_graphics_dir}/tizen/egl-sync-implementation-tizen.cpp ) # module: graphics, backend: ubuntu SET( adaptor_graphics_ubuntu_src_files ${adaptor_graphics_dir}/generic/egl-image-extensions-generic.cpp + ${adaptor_graphics_dir}/generic/egl-sync-implementation.cpp ) # module: graphics, backend: libuv-x11 SET( adaptor_graphics_x11_src_files ${adaptor_graphics_dir}/generic/egl-image-extensions-generic.cpp + ${adaptor_graphics_dir}/generic/egl-sync-implementation.cpp ) # module: graphics, backend: android SET( adaptor_graphics_android_src_files ${adaptor_graphics_dir}/android/egl-image-extensions-android.cpp + ${adaptor_graphics_dir}/android/egl-sync-implementation-android.cpp ) # module: graphics, backend: windows SET( adaptor_graphics_windows_src_files ${adaptor_graphics_dir}/windows-gl/egl-image-extensions.cpp + ${adaptor_graphics_dir}/windows/egl-sync-implementation-windows.cpp ) # module: graphics, backend: macos SET( adaptor_graphics_macos_src_files ${adaptor_graphics_dir}/macos/egl-image-extensions.cpp + ${adaptor_graphics_dir}/macos/egl-sync-implementation-macos.cpp ) # include GLES implementation diff --git a/dali/internal/graphics/generic/egl-sync-implementation.cpp b/dali/internal/graphics/generic/egl-sync-implementation.cpp new file mode 100644 index 0000000..842407f --- /dev/null +++ b/dali/internal/graphics/generic/egl-sync-implementation.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES + +#include + +// INTERNAL INCLUDES +#include +#include + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogSyncFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FENCE_SYNC"); +#endif + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +EglSyncObject::EglSyncObject(EglImplementation& eglImpl) +: mPollCounter(3), + mEglImplementation(eglImpl) +{ + EGLDisplay display = mEglImplementation.GetDisplay(); + mEglSync = eglCreateSync(display, EGL_SYNC_FENCE, NULL); +} + +EglSyncObject::~EglSyncObject() +{ + if(mEglSync && mEglImplementation.IsGlesInitialized()) + { + EGLDisplay display = mEglImplementation.GetDisplay(); + eglDestroySync(display, mEglSync); + } +} + +bool EglSyncObject::IsSynced() +{ + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync\n"); + auto result = eglClientWaitSync(mEglImplementation.GetDisplay(), mEglSync, 0 | EGL_SYNC_FLUSH_COMMANDS_BIT, 0); + + if(result == EGL_FALSE) + { + EGLint error = eglGetError(); + if(EGL_SUCCESS != error) + { + DALI_LOG_ERROR("eglClientSyncWait failed: %#0.4x\n", error); + } + } + else if(result == EGL_CONDITION_SATISFIED) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync Synced!\n"); + return true; + } + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync not synced :(\n"); + return false; +} + +void EglSyncObject::Wait() +{ + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglWaitSync\n"); + if(!eglWaitSync(mEglImplementation.GetDisplay(), mEglSync, 0)) + { + EGLint error = eglGetError(); + if(EGL_SUCCESS != error) + { + DALI_LOG_ERROR("eglSyncWait failed: %#0.4x\n", error); + } + } +} + +void EglSyncObject::ClientWait() +{ + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglWaitSync (blocking)\n"); + auto result = eglClientWaitSync(mEglImplementation.GetDisplay(), mEglSync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER); + if(result == EGL_FALSE) + { + EGLint error = eglGetError(); + if(EGL_SUCCESS != error) + { + DALI_LOG_ERROR("eglSyncWait failed: %#0.4x\n", error); + } + } + else if(result == EGL_CONDITION_SATISFIED) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync Synced!\n"); + } +} + +EglSyncImplementation::EglSyncImplementation() +: mEglImplementation(NULL), + mSyncInitialized(false), + mSyncInitializeFailed(false) +{ +} + +EglSyncImplementation::~EglSyncImplementation() +{ +} + +void EglSyncImplementation::Initialize(EglImplementation* eglImpl) +{ + mEglImplementation = eglImpl; +} + +Integration::GraphicsSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject() +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + return new EglSyncObject(*mEglImplementation); +} + +void EglSyncImplementation::DestroySyncObject(Integration::GraphicsSyncAbstraction::SyncObject* syncObject) +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + delete static_cast(syncObject); +} + +void EglSyncImplementation::InitializeEglSync() +{ +} + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali diff --git a/dali/internal/graphics/gles-impl/egl-sync-object.cpp b/dali/internal/graphics/gles-impl/egl-sync-object.cpp index 14410b4..44dd8f4 100644 --- a/dali/internal/graphics/gles-impl/egl-sync-object.cpp +++ b/dali/internal/graphics/gles-impl/egl-sync-object.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/dali/internal/graphics/gles-impl/egl-sync-object.h b/dali/internal/graphics/gles-impl/egl-sync-object.h index d014a7f..05ad261 100644 --- a/dali/internal/graphics/gles-impl/egl-sync-object.h +++ b/dali/internal/graphics/gles-impl/egl-sync-object.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_EGL_SYNC_OBJECT_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ // INTERNAL INCLUDES #include +//#include namespace Dali::Internal::Adaptor { class EglSyncImplementation; @@ -34,6 +35,9 @@ namespace Dali::Graphics::EGL { using SyncObjectResource = GLES::Resource; +/** + * Proxy to EglSyncObject that also implements a graphics resource + */ class SyncObject : public SyncObjectResource { public: diff --git a/dali/internal/graphics/gles-impl/gles-context.cpp b/dali/internal/graphics/gles-impl/gles-context.cpp index b7e2b5e..c90b2a8 100644 --- a/dali/internal/graphics/gles-impl/gles-context.cpp +++ b/dali/internal/graphics/gles-impl/gles-context.cpp @@ -378,8 +378,8 @@ void Context::Flush(bool reset, const GLES::DrawCallDescriptor& drawCall, GLES:: texture->InitializeResource(); } - // Warning, this may cause glWaitSync to occur on the GPU. - dependencyChecker.CheckNeedsSync(this, texture); + // Warning, this may cause glWaitSync to occur on the GPU, or glClientWaitSync to block the CPU. + dependencyChecker.CheckNeedsSync(this, texture, true); texture->Bind(binding); texture->Prepare(); diff --git a/dali/internal/graphics/gles-impl/gles-sync-object.cpp b/dali/internal/graphics/gles-impl/gles-sync-object.cpp index f44fdc3..1d1bc11 100644 --- a/dali/internal/graphics/gles-impl/gles-sync-object.cpp +++ b/dali/internal/graphics/gles-impl/gles-sync-object.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/dali/internal/graphics/gles-impl/gles-sync-object.h b/dali/internal/graphics/gles-impl/gles-sync-object.h index 32a89f6..37d0a81 100644 --- a/dali/internal/graphics/gles-impl/gles-sync-object.h +++ b/dali/internal/graphics/gles-impl/gles-sync-object.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_GLES_SYNC_OBJECT_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +35,9 @@ namespace Dali::Graphics::GLES { using SyncObjectResource = Resource; +/** + * Class that maintains a glFenceSync object. + */ class SyncObject : public SyncObjectResource { public: diff --git a/dali/internal/graphics/gles-impl/gles-sync-pool.cpp b/dali/internal/graphics/gles-impl/gles-sync-pool.cpp index 770deb0..c4cd399 100644 --- a/dali/internal/graphics/gles-impl/gles-sync-pool.cpp +++ b/dali/internal/graphics/gles-impl/gles-sync-pool.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,46 +22,128 @@ // Internal Headers #include +#include + +#if defined(DEBUG_ENABLED) +extern Debug::Filter* gLogSyncFilter; +#endif namespace Dali::Graphics::GLES { -AgingSyncObject::AgingSyncObject(Graphics::EglGraphicsController& controller, const Context* writeContext) +AgingSyncObject::AgingSyncObject(Graphics::EglGraphicsController& controller, const Context* writeContext, bool _egl) : controller(controller), - writeContext(writeContext) + writeContext(writeContext), + egl(_egl) { - auto gl = controller.GetGL(); - if(gl) + if(egl) + { + eglSyncObject = static_cast(controller.GetEglSyncImplementation().CreateSyncObject()); + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::cons; EGL::CreateSyncObject: %p\n", eglSyncObject); + } + else { - glSyncObject = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + auto gl = controller.GetGL(); + if(gl) + { + glSyncObject = gl->FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + } } } AgingSyncObject::~AgingSyncObject() { - auto gl = controller.GetGL(); - if(gl && glSyncObject != nullptr) + if(!controller.IsShuttingDown()) { - gl->DeleteSync(glSyncObject); + if(egl) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::dstr; EGL::DestroySyncObject: %p\n", eglSyncObject); + controller.GetEglSyncImplementation().DestroySyncObject(eglSyncObject); + } + else + { + auto gl = controller.GetGL(); + if(gl && glSyncObject != nullptr) + { + gl->DeleteSync(glSyncObject); + } + } + } +} + +bool AgingSyncObject::ClientWait() +{ + bool synced = false; + if(egl) + { + if(eglSyncObject) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::ClientWait(); EGL::ClientWaitSync\n"); + eglSyncObject->ClientWait(); + synced = true; + } + } + else + { + auto gl = controller.GetGL(); + if(gl && glSyncObject) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::ClientWait(); glClientWaitSync 1ms\n"); + const GLuint64 TIMEOUT = 1000000; //1ms! + GLenum result = gl->ClientWaitSync(glSyncObject, GL_SYNC_FLUSH_COMMANDS_BIT, TIMEOUT); + + synced = (result == GL_ALREADY_SIGNALED || result == GL_CONDITION_SATISFIED); + } + } + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::ClientWait(); Result: %s\n", synced ? "Synced" : "NOT SYNCED"); + return synced; +} + +void AgingSyncObject::Wait() +{ + if(egl) + { + if(eglSyncObject) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::Wait(); EGL::WaitSync\n"); + eglSyncObject->Wait(); + } + } + else + { + auto gl = controller.GetGL(); + if(gl && glSyncObject) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::Wait(); glWaitSync\n"); + gl->WaitSync(glSyncObject, 0, 0ull); + } } } SyncPool::~SyncPool() = default; -AgingSyncObject* SyncPool::AllocateSyncObject(const Context* writeContext) +AgingSyncObject* SyncPool::AllocateSyncObject(const Context* writeContext, SyncPool::SyncContext syncContext) { - std::unique_ptr syncObject = std::make_unique(mController, writeContext); + std::unique_ptr syncObject = std::make_unique(mController, writeContext, (syncContext == SyncContext::EGL)); mSyncObjects.push_back(std::move(syncObject)); return mSyncObjects.back().get(); } void SyncPool::Wait(AgingSyncObject* syncPoolObject) { - auto gl = mController.GetGL(); - if(gl && syncPoolObject->glSyncObject != nullptr) + if(syncPoolObject != nullptr) { syncPoolObject->syncing = true; - gl->WaitSync(syncPoolObject->glSyncObject, 0, GL_TIMEOUT_IGNORED); + syncPoolObject->Wait(); + } +} + +bool SyncPool::ClientWait(AgingSyncObject* syncPoolObject) +{ + if(syncPoolObject) + { + return syncPoolObject->ClientWait(); } + return false; } void SyncPool::FreeSyncObject(AgingSyncObject* agingSyncObject) @@ -79,12 +161,14 @@ void SyncPool::FreeSyncObject(AgingSyncObject* agingSyncObject) */ void SyncPool::AgeSyncObjects() { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgeSyncObjects: count: %d\n", mSyncObjects.size()); + if(!mSyncObjects.empty()) { // Age the remaining sync objects. for(auto& agingSyncObject : mSyncObjects) { - if(agingSyncObject != nullptr && agingSyncObject->glSyncObject != 0) + if(agingSyncObject != nullptr && (agingSyncObject->glSyncObject != 0 || agingSyncObject->eglSyncObject != nullptr)) { if(agingSyncObject->age > 0) { @@ -100,6 +184,8 @@ void SyncPool::AgeSyncObjects() // Move any old sync objects to the end of the list, and then remove them all. mSyncObjects.erase(std::remove_if(mSyncObjects.begin(), mSyncObjects.end(), [&](std::unique_ptr& agingSyncObject) { return agingSyncObject == nullptr; }), mSyncObjects.end()); + + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgeSyncObjects: count after erase: %d\n", mSyncObjects.size()); } } // namespace Dali::Graphics::GLES diff --git a/dali/internal/graphics/gles-impl/gles-sync-pool.h b/dali/internal/graphics/gles-impl/gles-sync-pool.h index d394b03..e92cdf0 100644 --- a/dali/internal/graphics/gles-impl/gles-sync-pool.h +++ b/dali/internal/graphics/gles-impl/gles-sync-pool.h @@ -2,7 +2,7 @@ #define DALI_GRAPHICS_GLES_SYNC_POOL_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,14 @@ #include #include -namespace Dali::Graphics +namespace Dali +{ +namespace Internal::Adaptor +{ +class EglSyncObject; +} + +namespace Graphics { class EglGraphicsController; @@ -31,14 +38,22 @@ class Context; struct AgingSyncObject { - AgingSyncObject(Graphics::EglGraphicsController& controller, const Context* writeContext); + AgingSyncObject(Graphics::EglGraphicsController& controller, const Context* writeContext, bool egl = false); ~AgingSyncObject(); EglGraphicsController& controller; const Context* writeContext; - GLsync glSyncObject{0}; - uint8_t age{2}; - bool syncing{false}; + union + { + GLsync glSyncObject; + Internal::Adaptor::EglSyncObject* eglSyncObject; + }; + uint8_t age{2}; + bool syncing{false}; + bool egl{false}; + + void Wait(); + bool ClientWait(); }; using AgingSyncPtrRef = std::unique_ptr&; @@ -51,6 +66,12 @@ using AgingSyncPtrRef = std::unique_ptr&; class SyncPool { public: + enum class SyncContext + { + EGL, ///< Use EGL sync when syncing between multiple contexts + GL ///< Use GL sync when syncing in the same context + }; + explicit SyncPool(Graphics::EglGraphicsController& graphicsController) : mController(graphicsController) { @@ -63,19 +84,26 @@ public: * @param writeContext * @return An owned ptr to a sync object */ - AgingSyncObject* AllocateSyncObject(const Context* writeContext); + AgingSyncObject* AllocateSyncObject(const Context* writeContext, SyncContext syncContext); /** - * Wait on a sync object in any context + * Wait on a sync object in any context in the GPU * @param syncPoolObject The object to wait on. */ void Wait(AgingSyncObject* syncPoolObject); /** + * Wait on a sync object in any context in the CPU + * @param syncPoolObject The object to wait on. + * @return true if the sync object was signaled, false if it timed out + */ + bool ClientWait(AgingSyncObject* syncPoolObject); + + /** * Delete the sync object if it's not needed. - * + * @param syncPoolObject The object to delete. */ - void FreeSyncObject(AgingSyncObject* agingSyncObject); + void FreeSyncObject(AgingSyncObject* syncPoolObject); /** * Age outstanding sync objects. Call at the end of each frame. @@ -89,6 +117,7 @@ private: }; } // namespace GLES -} // namespace Dali::Graphics +} // namespace Graphics +} // namespace Dali #endif //DALI_GRAPHICS_GLES_SYNC_POOL_H diff --git a/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp b/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp index cb0ed25..0ce3e44 100644 --- a/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp +++ b/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,8 +18,13 @@ #include "gles-texture-dependency-checker.h" // EXTERNAL INCLUDES +#include #include +#if defined(DEBUG_ENABLED) +extern Debug::Filter* gLogSyncFilter; +#endif + namespace Dali::Graphics::GLES { void TextureDependencyChecker::Reset() @@ -70,12 +75,16 @@ void TextureDependencyChecker::AddTextures(const GLES::Context* writeContext, co texture->SetDependencyIndex(index); } } - textureDependency.writeContext = const_cast(writeContext); - textureDependency.framebuffer = const_cast(framebuffer); - textureDependency.agingSyncObject = mController.GetSyncPool().AllocateSyncObject(writeContext); + textureDependency.writeContext = const_cast(writeContext); + textureDependency.framebuffer = const_cast(framebuffer); + + // We have to check on different EGL contexts: The shared resource context is used to write to fbos, + // but they are usually drawn onto separate scene context. + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::AddTextures() Allocating sync object\n"); + textureDependency.agingSyncObject = mController.GetSyncPool().AllocateSyncObject(writeContext, SyncPool::SyncContext::EGL); } -void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext, const GLES::Texture* texture) +void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext, const GLES::Texture* texture, bool cpu) { uint32_t dependencyIndex = texture->GetDependencyIndex(); if(dependencyIndex < mTextureDependencies.size()) @@ -86,9 +95,19 @@ void TextureDependencyChecker::CheckNeedsSync(const GLES::Context* readContext, // Needs syncing! textureDependency.syncing = true; - // Wait on the sync object in GPU. This will ensure that the writeContext completes its tasks prior - // to the sync point. - mController.GetSyncPool().Wait(textureDependency.agingSyncObject); + if(cpu) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CheckNeedsSync Insert CPU WAIT"); + mController.GetSyncPool().ClientWait(textureDependency.agingSyncObject); + } + else + { + // Wait on the sync object in GPU. This will ensure that the writeContext completes its tasks prior + // to the sync point. + // However, this may instead timeout, and we can't tell the difference (at least, for glFenceSync) + DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CheckNeedsSync Insert GPU WAIT"); + mController.GetSyncPool().Wait(textureDependency.agingSyncObject); + } } } } diff --git a/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h b/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h index 8861229..63b1127 100644 --- a/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h +++ b/dali/internal/graphics/gles-impl/gles-texture-dependency-checker.h @@ -2,7 +2,7 @@ #define DALI_GLES_TEXTURE_DEPENDENCY_CHECKER_H /* - * Copyright (c) 2022 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -63,12 +63,21 @@ public: /** * Check if the given texture needs syncing before being read. This - * will perform a glWaitSync() (GPU side semaphore) if the texture - * needs syncing. + * will perform either a glWaitSync() (GPU side semaphore), or a + * glClientWaitSync(CPU fence) if the texture needs syncing. * @param[in] readContext The context that the texture is being read (drawn with) * @param[in] texture The texture being read + * @param[in] cpuSync True if glClientWaitSync should be used instead of glWaitSync */ - void CheckNeedsSync(const Context* readContext, const Texture* texture); + void CheckNeedsSync(const Context* readContext, const Texture* texture, bool cpuSync = false); + + /** + * Get the number of (offscreen) textures for dependency checking + */ + size_t GetTextureCount() const + { + return mTextureDependencies.size(); + } private: struct TextureDependency diff --git a/dali/internal/graphics/gles/egl-sync-implementation.h b/dali/internal/graphics/gles/egl-sync-implementation.h index 6a29ca9..b1bd6ad 100644 --- a/dali/internal/graphics/gles/egl-sync-implementation.h +++ b/dali/internal/graphics/gles/egl-sync-implementation.h @@ -2,7 +2,7 @@ #define DALI_INTERNAL_ADAPTOR_EGL_SYNC_IMPLEMENTATION_H /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,11 +50,24 @@ public: bool IsSynced() override; + /** + * Set up a GPU wait (returns immediately on CPU) for this sync. Can work across + * EGL contexts. + */ + void Wait() override; + + /** + * Wait on the CPU until the GPU executes this sync. Warning: could be a long time! + * Can work across EGL contexts. + */ + void ClientWait() override; + private: #ifdef _ARCH_ARM_ EGLSyncKHR mEglSync; #else - int mPollCounter; // Implementations without fence sync use a 3 frame counter + EGLSync mEglSync; + int mPollCounter; // Implementations without fence sync use a 3 frame counter #endif EglImplementation& mEglImplementation; }; diff --git a/dali/internal/graphics/macos/egl-sync-implementation-macos.cpp b/dali/internal/graphics/macos/egl-sync-implementation-macos.cpp new file mode 100644 index 0000000..df12970 --- /dev/null +++ b/dali/internal/graphics/macos/egl-sync-implementation-macos.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES + +#include + +// INTERNAL INCLUDES +#include +#include + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogSyncFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FENCE_SYNC"); +#endif + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +EglSyncObject::EglSyncObject(EglImplementation& eglImpl) +: mPollCounter(3), + mEglImplementation(eglImpl) +{ +} + +EglSyncObject::~EglSyncObject() +{ +} + +bool EglSyncObject::IsSynced() +{ + return true; +} + +void EglSyncObject::Wait() +{ +} + +void EglSyncObject::ClientWait() +{ +} + +EglSyncImplementation::EglSyncImplementation() +: mEglImplementation(NULL), + mSyncInitialized(false), + mSyncInitializeFailed(false) +{ +} + +EglSyncImplementation::~EglSyncImplementation() +{ +} + +void EglSyncImplementation::Initialize(EglImplementation* eglImpl) +{ + mEglImplementation = eglImpl; +} + +Integration::GraphicsSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject() +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + return new EglSyncObject(*mEglImplementation); +} + +void EglSyncImplementation::DestroySyncObject(Integration::GraphicsSyncAbstraction::SyncObject* syncObject) +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + delete static_cast(syncObject); +} + +void EglSyncImplementation::InitializeEglSync() +{ +} + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali diff --git a/dali/internal/graphics/gles/egl-sync-implementation.cpp b/dali/internal/graphics/tizen/egl-sync-implementation-tizen.cpp similarity index 70% rename from dali/internal/graphics/gles/egl-sync-implementation.cpp rename to dali/internal/graphics/tizen/egl-sync-implementation-tizen.cpp index 8398c1b..d840015 100644 --- a/dali/internal/graphics/gles/egl-sync-implementation.cpp +++ b/dali/internal/graphics/tizen/egl-sync-implementation-tizen.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ #include // INTERNAL INCLUDES +#include #include #ifdef _ARCH_ARM_ @@ -39,9 +40,14 @@ static PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = NULL; static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = NULL; static PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = NULL; +static PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = NULL; #endif +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogSyncFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FENCE_SYNC"); +#endif + namespace Dali { namespace Internal @@ -50,9 +56,9 @@ namespace Adaptor { #ifdef _ARCH_ARM_ -EglSyncObject::EglSyncObject(EglImplementation& eglSyncImpl) +EglSyncObject::EglSyncObject(EglImplementation& eglImpl) : mEglSync(NULL), - mEglImplementation(eglSyncImpl) + mEglImplementation(eglImpl) { EGLDisplay display = mEglImplementation.GetDisplay(); mEglSync = eglCreateSyncKHR(display, EGL_SYNC_FENCE_KHR, NULL); @@ -61,6 +67,10 @@ EglSyncObject::EglSyncObject(EglImplementation& eglSyncImpl) DALI_LOG_ERROR("eglCreateSyncKHR failed %#0.4x\n", eglGetError()); mEglSync = NULL; } + else + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglCreateSyncKHR Success: %p\n", mEglSync); + } } EglSyncObject::~EglSyncObject() @@ -73,6 +83,10 @@ EglSyncObject::~EglSyncObject() { DALI_LOG_ERROR("eglDestroySyncKHR failed %#0.4x\n", error); } + else + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglDestroySyncKHR Success: %p\n", mEglSync); + } } } @@ -82,6 +96,7 @@ bool EglSyncObject::IsSynced() if(mEglSync != NULL) { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync no timeout\n"); EGLint result = eglClientWaitSyncKHR(mEglImplementation.GetDisplay(), mEglSync, 0, 0ull); EGLint error = eglGetError(); if(EGL_SUCCESS != error) @@ -94,9 +109,46 @@ bool EglSyncObject::IsSynced() } } + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync(%p, 0, 0) %s\n", mEglSync, synced ? "Synced" : "NOT SYNCED"); return synced; } +void EglSyncObject::ClientWait() +{ + bool synced = false; + if(mEglSync != nullptr) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync FOREVER\n"); + auto result = eglClientWaitSyncKHR(mEglImplementation.GetDisplay(), mEglSync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR); + if(result == EGL_FALSE) + { + Egl::PrintError(eglGetError()); + } + else if(result == EGL_CONDITION_SATISFIED_KHR) + { + synced = true; + } + } + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglClientWaitSync(%p, 0, FOREVER) %s\n", mEglSync, synced ? "Synced" : "NOT SYNCED"); +} + +void EglSyncObject::Wait() +{ + if(mEglSync != nullptr) + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglWaitSync\n"); + auto result = eglWaitSyncKHR(mEglImplementation.GetDisplay(), mEglSync, 0); + if(EGL_FALSE == result) + { + Egl::PrintError(eglGetError()); + } + else + { + DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglWaitSync() %p synced!\n", mEglSync); + } + } +} + EglSyncImplementation::EglSyncImplementation() : mEglImplementation(NULL), mSyncInitialized(false), @@ -152,10 +204,11 @@ void EglSyncImplementation::InitializeEglSync() { eglCreateSyncKHR = reinterpret_cast(eglGetProcAddress("eglCreateSyncKHR")); eglClientWaitSyncKHR = reinterpret_cast(eglGetProcAddress("eglClientWaitSyncKHR")); + eglWaitSyncKHR = reinterpret_cast(eglGetProcAddress("eglWaitSyncKHR")); eglDestroySyncKHR = reinterpret_cast(eglGetProcAddress("eglDestroySyncKHR")); } - if(eglCreateSyncKHR && eglClientWaitSyncKHR && eglDestroySyncKHR) + if(eglCreateSyncKHR && eglClientWaitSyncKHR && eglWaitSyncKHR && eglDestroySyncKHR) { mSyncInitialized = true; } @@ -179,12 +232,15 @@ EglSyncObject::~EglSyncObject() bool EglSyncObject::IsSynced() { - if(mPollCounter <= 0) - { - return true; - } - --mPollCounter; - return false; + return true; +} + +void EglSyncObject::Wait() +{ +} + +void EglSyncObject::ClientWait() +{ } EglSyncImplementation::EglSyncImplementation() diff --git a/dali/internal/graphics/windows-gl/egl-sync-implementation-windows.cpp b/dali/internal/graphics/windows-gl/egl-sync-implementation-windows.cpp new file mode 100644 index 0000000..df12970 --- /dev/null +++ b/dali/internal/graphics/windows-gl/egl-sync-implementation-windows.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES + +#include + +// INTERNAL INCLUDES +#include +#include + +#if defined(DEBUG_ENABLED) +Debug::Filter* gLogSyncFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_FENCE_SYNC"); +#endif + +namespace Dali +{ +namespace Internal +{ +namespace Adaptor +{ +EglSyncObject::EglSyncObject(EglImplementation& eglImpl) +: mPollCounter(3), + mEglImplementation(eglImpl) +{ +} + +EglSyncObject::~EglSyncObject() +{ +} + +bool EglSyncObject::IsSynced() +{ + return true; +} + +void EglSyncObject::Wait() +{ +} + +void EglSyncObject::ClientWait() +{ +} + +EglSyncImplementation::EglSyncImplementation() +: mEglImplementation(NULL), + mSyncInitialized(false), + mSyncInitializeFailed(false) +{ +} + +EglSyncImplementation::~EglSyncImplementation() +{ +} + +void EglSyncImplementation::Initialize(EglImplementation* eglImpl) +{ + mEglImplementation = eglImpl; +} + +Integration::GraphicsSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject() +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + return new EglSyncObject(*mEglImplementation); +} + +void EglSyncImplementation::DestroySyncObject(Integration::GraphicsSyncAbstraction::SyncObject* syncObject) +{ + DALI_ASSERT_ALWAYS(mEglImplementation && "Sync Implementation not initialized"); + delete static_cast(syncObject); +} + +void EglSyncImplementation::InitializeEglSync() +{ +} + +} // namespace Adaptor +} // namespace Internal +} // namespace Dali -- 2.7.4