// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. #pragma once #include "Engine/Threading/Task.h" #include "Engine/Platform/Platform.h" #include "GPUTasksContext.h" class GPUResource; /// /// Describes GPU work object. /// class GPUTask : public Task { friend GPUTasksContext; public: /// /// Describes GPU work type /// DECLARE_ENUM_4(Type, Custom, CopyResource, UploadTexture, UploadBuffer); /// /// Describes GPU work result value /// DECLARE_ENUM_4(Result, Ok, Failed, MissingResources, MissingData); private: /// /// Task type /// Type _type; /// /// Synchronization point when async task has been done /// GPUSyncPoint _syncPoint; /// /// The context that performed this task, it's should synchronize it. /// GPUTasksContext* _context; protected: /// /// Initializes a new instance of the class. /// /// The type. GPUTask(const Type type) : _type(type) , _syncPoint(0) , _context(nullptr) { } public: /// /// Gets a task type. /// /// The type. FORCE_INLINE Type GetType() const { return _type; } /// /// Gets work finish synchronization point /// /// Finish task sync point FORCE_INLINE GPUSyncPoint GetSyncPoint() const { return _syncPoint; } public: /// /// Checks if operation is syncing /// /// True if operation is syncing, otherwise false FORCE_INLINE bool IsSyncing() const { return IsRunning() && _syncPoint != 0; } public: /// /// Executes this task. /// /// The context. void Execute(GPUTasksContext* context); /// /// Action fired when asynchronous operation has been synchronized with a GPU /// void Sync() { if (_context != nullptr) { ASSERT(IsSyncing()); // Sync and finish _context = nullptr; OnSync(); OnFinish(); } } /// /// Cancels the task results synchronization. /// void CancelSync() { ASSERT(IsSyncing()); // Rollback state and cancel _context = nullptr; _state = TaskState::Queued; Cancel(); } protected: virtual Result run(GPUTasksContext* context) = 0; virtual void OnSync() { } public: // [Task] String ToString() const override; protected: // [Task] void Enqueue() override; bool Run() override { return true; } void OnCancel() override { // Check if task is waiting for sync (very likely situation) if (IsSyncing()) { // Task has been performed but is waiting for a CPU/GPU sync so we have to cancel that ASSERT(_context != nullptr); _context->OnCancelSync(this); _context = nullptr; _state = TaskState::Canceled; } else { // Maybe we could also handle cancel event during running but not yet syncing ASSERT(!IsRunning()); } // Base Task::OnCancel(); } };