surfaceInterface->MakeContextCurrent();
surfaceInterface->PostRender();
- // Delete discarded surface context sync objects.
+ // Delete discarded surface context sync objects, and create new syncfence for NativeImage texture.
// NOTE : We can assume that surface context is become current now.
// And also can asusme that ResolvePresentRenderTarget() will be called at most 1 times per each frame.
- mSyncPool.ProcessDiscardSyncObjects(GetSurfaceContext(surfaceInterface));
+ const auto* currentSurfaceContext = GetSurfaceContext(surfaceInterface);
+ mSyncPool.ProcessDiscardSyncObjects(currentSurfaceContext);
+
+#ifdef DALI_PROFILE_TV
+ /// Only TV profile should not create egl sync object before eglSwapBuffers, due to DDK bug. 2024-12-13. eunkiki.hong
+
+ // NOTE : We need to call eglCreateSyncKHR after eglSwapBuffer if that sync will not be used 'before' swap buffer.
+ // Since given sync fence try to store rendering result of current frame which we usually don't need,
+ // so GPU memory increased.
+ if(mTextureDependencyChecker.GetNativeTextureCount() > 0)
+ {
+ mTextureDependencyChecker.CreateNativeTextureSync(currentSurfaceContext);
+
+ // Need to call glFlush or eglSwapBuffer after create sync object.
+ mGlAbstraction->Flush();
+ }
+#endif
}
}
void EglGraphicsController::PostRender()
{
+#ifdef DALI_PROFILE_TV
+ /// Only TV profile should not create egl sync object before eglSwapBuffers, due to DDK bug. 2024-12-13. eunkiki.hong
+ // eglCreateSyncKHR for FBO case.
+ if(mTextureDependencyChecker.GetNativeTextureCount() > 0)
+ {
+ mTextureDependencyChecker.CreateNativeTextureSync(mCurrentContext);
+
+ // Need to call glFlush or eglSwapBuffer after create sync object.
+ mGlAbstraction->Flush();
+ }
+#endif
+
mTextureDependencyChecker.Reset();
mSyncPool.AgeSyncObjects();
*/
dependencyChecker.AddTextures(this, framebuffer);
}
- }
- if(dependencyChecker.GetNativeTextureCount() > 0)
- {
- dependencyChecker.CreateNativeTextureSync(this);
+ if(dependencyChecker.GetNativeTextureCount() > 0)
+ {
+ dependencyChecker.MarkNativeTextureSyncContext(this);
+#ifndef DALI_PROFILE_TV
+ /// Only TV profile should not create egl sync object before eglSwapBuffers, due to DDK bug. 2024-12-13. eunkiki.hong
+ dependencyChecker.CreateNativeTextureSync(this);
+#endif
+ }
}
}
{
auto agingSyncObject = std::make_unique<AgingSyncObject>(mController, writeContext, (syncContext == SyncContext::EGL));
- auto syncPoolObjectId = mSyncObjectId++;
+ auto syncPoolObjectId = ++mSyncObjectId;
+ if(DALI_UNLIKELY(syncPoolObjectId == INVALID_SYNC_OBJECT_ID))
+ {
+ syncPoolObjectId = ++mSyncObjectId;
+ }
// Take ownership of sync object
mSyncObjects.insert(std::make_pair(syncPoolObjectId, std::move(agingSyncObject)));
public:
using SyncObjectId = uint32_t;
+ static constexpr SyncObjectId INVALID_SYNC_OBJECT_ID = 0u;
+
enum class SyncContext
{
EGL, ///< Use EGL sync when syncing between multiple contexts
/**
* Check whether given object is synced in the CPU
- * @param syncPoolObjectId The id of object to check synced.
+ * @param syncPoolObjectId The id of object to check synced. If it's invalid, return false immediately.
* @return true if the sync object was signaled, false if it timed out
*/
bool IsSynced(SyncObjectId syncPoolObjectId);
/**
* Wait on a sync object in any context in the GPU
- * @param syncPoolObjectId The id of object to wait on.
+ * @param syncPoolObjectId The id of object to wait on. If it's invalid, do nothing.
*/
void Wait(SyncObjectId syncPoolObjectId);
/**
* Wait on a sync object in any context in the CPU
- * @param syncPoolObjectId The id of object to wait on.
+ * @param syncPoolObjectId The id of object to wait on. If it's invalid, return false immediately.
* @return true if the sync object was signaled, false if it timed out
*/
bool ClientWait(SyncObjectId syncPoolObjectId);
/**
* Delete the sync object if it's not needed.
- * @param syncPoolObjectId The id of object to delete.
+ * @param syncPoolObjectId The id of object to delete. If it's invalid, do nothing.
*/
void FreeSyncObject(SyncObjectId syncPoolObjectId);
EglGraphicsController& mController;
- SyncObjectId mSyncObjectId{0u};
+ SyncObjectId mSyncObjectId{INVALID_SYNC_OBJECT_ID};
};
} // namespace GLES
if(!mNativeTextureDependencies[0].empty() || !mNativeTextureDependencies[1].empty())
{
- DALI_ASSERT_ALWAYS(mIsFirstPreparedNativeTextureDependency && "CreateNativeTextureSync should be called before PostRender!");
+ DALI_ASSERT_ALWAYS(mIsFirstPreparedNativeTextureDependency && "MarkNativeTextureSyncContext should be called before PostRender!");
// Remove all infomations about previous native textures
for(auto& nativeTextureDependency : mNativeTextureDependencies[mPreviousNativeTextureDependencyIndex])
if(dependencyIndex < mFramebufferTextureDependencies.size())
{
auto& textureDependency = mFramebufferTextureDependencies[dependencyIndex];
- if(!textureDependency.syncing && textureDependency.writeContext != readContext)
+ if(!textureDependency.syncing && textureDependency.writeContext != readContext && textureDependency.agingSyncObjectId != INVALID_SYNC_OBJECT_ID)
{
// Needs syncing!
textureDependency.syncing = true;
if(cpu)
{
DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CheckNeedsSync Insert CPU WAIT");
- mController.GetSyncPool().ClientWait(textureDependency.agingSyncObjectId);
+ const bool synced = mController.GetSyncPool().ClientWait(textureDependency.agingSyncObjectId);
+ if(DALI_LIKELY(synced))
+ {
+ // Object discarded, and will be free when write context be currnt.
+ mController.GetSyncPool().FreeSyncObject(textureDependency.agingSyncObjectId);
+ textureDependency.agingSyncObjectId = INVALID_SYNC_OBJECT_ID;
+ }
}
else
{
// TODO : Optimize here. For now, we don't have too much EndPass call. So just keep this logic.
for(auto& nativeTextureDependency : mNativeTextureDependencies[mPreviousNativeTextureDependencyIndex])
{
- if(nativeTextureDependency.synced)
+ if(nativeTextureDependency.synced || nativeTextureDependency.agingSyncObjectId == INVALID_SYNC_OBJECT_ID)
{
- // Fast-out if we know it is already synced
+ // Fast-out if we know it is already synced, or if there's no sync object.
continue;
}
DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CheckNeedsSync (for native) Insert CPU WAIT");
nativeTextureDependency.synced = mController.GetSyncPool().ClientWait(nativeTextureDependency.agingSyncObjectId);
- if(DALI_LIKELY(nativeTextureDependency.synced) && readContext == nativeTextureDependency.writeContext)
+ if(DALI_LIKELY(nativeTextureDependency.synced))
{
- // We can free sync object immediatly if we are using same context.
+ // Object discarded, and will be free when write context be currnt.
mController.GetSyncPool().FreeSyncObject(nativeTextureDependency.agingSyncObjectId);
+ nativeTextureDependency.agingSyncObjectId = INVALID_SYNC_OBJECT_ID;
}
}
else
}
}
-void TextureDependencyChecker::CreateNativeTextureSync(const GLES::Context* writeContext)
+void TextureDependencyChecker::MarkNativeTextureSyncContext(const GLES::Context* writeContext)
{
if(mIsFirstPreparedNativeTextureDependency)
{
{
auto& nativeTextureDependency = mNativeTextureDependencies[mCurrentNativeTextureDependencyIndex].back();
nativeTextureDependency.writeContext = writeContext; // Store write context
+ }
+}
- DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CreateNativeTextureSync() Allocating sync object\n");
- nativeTextureDependency.agingSyncObjectId = mController.GetSyncPool().AllocateSyncObject(writeContext, SyncPool::SyncContext::EGL);
+void TextureDependencyChecker::CreateNativeTextureSync(const GLES::Context* currentContext)
+{
+ // TODO : Optimize here. For now, we don't have too much EndPass call. So just keep this logic.
+ for(auto& nativeTextureDependency : mNativeTextureDependencies[mCurrentNativeTextureDependencyIndex])
+ {
+ if(nativeTextureDependency.writeContext == currentContext && nativeTextureDependency.agingSyncObjectId == INVALID_SYNC_OBJECT_ID)
+ {
+ DALI_LOG_INFO(gLogSyncFilter, Debug::Verbose, "TextureDependencyChecker::CreateNativeTextureSync(%p) Allocating sync object\n", currentContext);
+ nativeTextureDependency.agingSyncObjectId = mController.GetSyncPool().AllocateSyncObject(currentContext, SyncPool::SyncContext::EGL);
+ }
}
}
void DiscardNativeTexture(const Texture* texture);
/**
- * @brief Create Sync object for native images.
+ * @brief Mark that native images write context.
* It will be called at EndRenderPass.
*/
- void CreateNativeTextureSync(const Context* writeContext);
+ void MarkNativeTextureSyncContext(const Context* writeContext);
+
+ /**
+ * @brief Create Sync object for native images.
+ * It will be called after eglSwapBuffers.
+ */
+ void CreateNativeTextureSync(const Context* currentContext);
private:
using SyncObjectId = uint32_t; ///< Note : It should be matched with Dali::Graphics::GLES::SyncPool:SyncObjectId.
+ static constexpr SyncObjectId INVALID_SYNC_OBJECT_ID = 0u; ///< Note : It should be matched with Dali::Graphics::GLES::SyncPool:INVALID_SYNC_OBJECT_ID.
+
struct FramebufferTextureDependency
{
std::vector<Texture*> textures;
Context* writeContext{nullptr};
Framebuffer* framebuffer{nullptr};
- SyncObjectId agingSyncObjectId{0u};
+ SyncObjectId agingSyncObjectId{INVALID_SYNC_OBJECT_ID};
bool syncing{false};
};
std::vector<FramebufferTextureDependency> mFramebufferTextureDependencies;
{
std::unordered_set<const Texture*> textures;
const Context* writeContext{nullptr};
- SyncObjectId agingSyncObjectId{0u};
+ SyncObjectId agingSyncObjectId{INVALID_SYNC_OBJECT_ID};
bool synced{false};
};
std::vector<NativeTextureDependency> mNativeTextureDependencies[2];