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();
#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.
public:
TestSyncObject(TraceCallStack& trace);
~TestSyncObject() override;
- bool IsSynced() override;
+ bool IsSynced() override;
+ void Wait() override;
+ void ClientWait() override;
+
bool synced;
TraceCallStack& mTrace;
};
#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.
#include <dali/graphics-api/graphics-sync-object-create-info.h>
#include <dali/graphics-api/graphics-sync-object.h>
-
-#include <test-graphics-sync-impl.h>
+#include "test-graphics-sync-impl.h"
namespace Dali
{
--- /dev/null
+/*
+ * 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 <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-debug.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+#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<EglSyncObject*>(syncObject);
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
#include <EGL/egl.h>
// Undef unneded symbols that fail to compile on MS Windows
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) /* Win32 and WinCE */
+
#undef ERROR
#undef OPAQUE
#undef max
#undef DIFFERENCE
+#endif
#include <EGL/eglext.h>
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
# 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
--- /dev/null
+/*
+ * 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 <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-debug.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+#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<EglSyncObject*>(syncObject);
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
/*
- * 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.
#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.
// INTERNAL INCLUDES
#include <dali/internal/graphics/gles-impl/gles-graphics-resource.h>
+//#include <dali/internal/graphics/gles/egl-sync-implementation.h>
namespace Dali::Internal::Adaptor
{
class EglSyncImplementation;
{
using SyncObjectResource = GLES::Resource<Graphics::SyncObject, Graphics::SyncObjectCreateInfo>;
+/**
+ * Proxy to EglSyncObject that also implements a graphics resource
+ */
class SyncObject : public SyncObjectResource
{
public:
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();
/*
- * 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.
#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.
{
using SyncObjectResource = Resource<Graphics::SyncObject, Graphics::SyncObjectCreateInfo>;
+/**
+ * Class that maintains a glFenceSync object.
+ */
class SyncObject : public SyncObjectResource
{
public:
/*
- * 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.
// Internal Headers
#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
+#include <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+#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<Internal::Adaptor::EglSyncObject*>(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
+ {
+ if(glSyncObject)
+ {
+ DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::ClientWait(); glClientWaitSync 1ms\n");
+ const GLuint64 TIMEOUT = 1000000; //1ms!
+ auto gl = controller.GetGL();
+ 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
+ {
+ if(glSyncObject)
+ {
+ DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgingSyncObject::Wait(); glWaitSync\n");
+ auto gl = controller.GetGL();
+ 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<AgingSyncObject> syncObject = std::make_unique<AgingSyncObject>(mController, writeContext);
+ std::unique_ptr<AgingSyncObject> syncObject = std::make_unique<AgingSyncObject>(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)
*/
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)
{
// 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>& agingSyncObject) { return agingSyncObject == nullptr; }),
mSyncObjects.end());
+
+ DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "AgeSyncObjects: count after erase: %d\n", mSyncObjects.size());
}
} // namespace Dali::Graphics::GLES
#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.
#include <dali/integration-api/gl-abstraction.h>
#include <dali/public-api/common/vector-wrapper.h>
-namespace Dali::Graphics
+namespace Dali
+{
+namespace Internal::Adaptor
+{
+class EglSyncObject;
+}
+
+namespace Graphics
{
class EglGraphicsController;
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<AgingSyncObject>&;
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)
{
* @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.
};
} // namespace GLES
-} // namespace Dali::Graphics
+} // namespace Graphics
+} // namespace Dali
#endif //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.
#include "gles-texture-dependency-checker.h"
// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
#include <dali/internal/graphics/gles-impl/egl-graphics-controller.h>
+#if defined(DEBUG_ENABLED)
+extern Debug::Filter* gLogSyncFilter;
+#endif
+
namespace Dali::Graphics::GLES
{
void TextureDependencyChecker::Reset()
texture->SetDependencyIndex(index);
}
}
- textureDependency.writeContext = const_cast<GLES::Context*>(writeContext);
- textureDependency.framebuffer = const_cast<GLES::Framebuffer*>(framebuffer);
- textureDependency.agingSyncObject = mController.GetSyncPool().AllocateSyncObject(writeContext);
+ textureDependency.writeContext = const_cast<GLES::Context*>(writeContext);
+ textureDependency.framebuffer = const_cast<GLES::Framebuffer*>(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())
// 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);
+ }
}
}
}
#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.
/**
* 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
#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.
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;
};
--- /dev/null
+/*
+ * 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 <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-debug.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+#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<EglSyncObject*>(syncObject);
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
/*
- * 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.
#include <dali/integration-api/debug.h>
// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-debug.h>
#include <dali/internal/graphics/gles/egl-implementation.h>
#ifdef _ARCH_ARM_
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
{
#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);
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()
{
DALI_LOG_ERROR("eglDestroySyncKHR failed %#0.4x\n", error);
}
+ else
+ {
+ DALI_LOG_INFO(gLogSyncFilter, Debug::General, "eglDestroySyncKHR Success: %p\n", mEglSync);
+ }
}
}
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)
}
}
+ 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),
{
eglCreateSyncKHR = reinterpret_cast<PFNEGLCREATESYNCKHRPROC>(eglGetProcAddress("eglCreateSyncKHR"));
eglClientWaitSyncKHR = reinterpret_cast<PFNEGLCLIENTWAITSYNCKHRPROC>(eglGetProcAddress("eglClientWaitSyncKHR"));
+ eglWaitSyncKHR = reinterpret_cast<PFNEGLWAITSYNCKHRPROC>(eglGetProcAddress("eglWaitSyncKHR"));
eglDestroySyncKHR = reinterpret_cast<PFNEGLDESTROYSYNCKHRPROC>(eglGetProcAddress("eglDestroySyncKHR"));
}
- if(eglCreateSyncKHR && eglClientWaitSyncKHR && eglDestroySyncKHR)
+ if(eglCreateSyncKHR && eglClientWaitSyncKHR && eglWaitSyncKHR && eglDestroySyncKHR)
{
mSyncInitialized = true;
}
bool EglSyncObject::IsSynced()
{
- if(mPollCounter <= 0)
- {
- return true;
- }
- --mPollCounter;
- return false;
+ return true;
+}
+
+void EglSyncObject::Wait()
+{
+}
+
+void EglSyncObject::ClientWait()
+{
}
EglSyncImplementation::EglSyncImplementation()
--- /dev/null
+/*
+ * 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 <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-debug.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+#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<EglSyncObject*>(syncObject);
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali