diff --git a/Source/Engine/Graphics/Async/Tasks/GPUUploadTextureMipTask.h b/Source/Engine/Graphics/Async/Tasks/GPUUploadTextureMipTask.h index 06a837e06..92ca0ffc2 100644 --- a/Source/Engine/Graphics/Async/Tasks/GPUUploadTextureMipTask.h +++ b/Source/Engine/Graphics/Async/Tasks/GPUUploadTextureMipTask.h @@ -75,30 +75,11 @@ protected: dataSource += _slicePitch; } + UpdateResidency(texture); + return Result::Ok; } - void OnSync() override - { - auto texture = _texture.Get(); - if (texture) - { - if (_mipIndex == texture->HighestResidentMipIndex() - 1) - { - // Mark the new mip as loaded - texture->SetResidentMipLevels(texture->ResidentMipLevels() + 1); - } - else - { - // Mark the new mip and all lower ones as loaded (eg. when loading Model SDF texture mips at once but out of order) - texture->SetResidentMipLevels(Math::Max(texture->ResidentMipLevels(), texture->MipLevels() - _mipIndex)); - } - } - - // Base - GPUTask::OnSync(); - } - void OnEnd() override { _texture.Unlink(); @@ -106,4 +87,18 @@ protected: // Base GPUTask::OnEnd(); } + + void UpdateResidency(GPUTexture* texture) const + { + if (_mipIndex == texture->HighestResidentMipIndex() - 1) + { + // Mark the new mip as loaded + texture->SetResidentMipLevels(texture->ResidentMipLevels() + 1); + } + else + { + // Mark the new mip and all lower ones as loaded (eg. when loading Model SDF texture mips at once but out of order) + texture->SetResidentMipLevels(Math::Max(texture->ResidentMipLevels(), texture->MipLevels() - _mipIndex)); + } + } }; diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.cpp b/Source/Engine/Graphics/Textures/StreamingTexture.cpp index 93cfb4565..54e30c7d7 100644 --- a/Source/Engine/Graphics/Textures/StreamingTexture.cpp +++ b/Source/Engine/Graphics/Textures/StreamingTexture.cpp @@ -252,6 +252,7 @@ protected: void OnSync() override { + // Update residency _newTexture->SetResidentMipLevels(_uploadedMipCount); Swap(_streamingTexture->_texture, _newTexture); SAFE_DELETE_GPU_RESOURCE(_newTexture); @@ -409,6 +410,8 @@ protected: dataSource += dataPerSlice; } + UpdateResidency(texture); + return Result::Ok; } diff --git a/Source/Engine/Graphics/Textures/TextureBase.cpp b/Source/Engine/Graphics/Textures/TextureBase.cpp index 600bfcc2a..8e185c06a 100644 --- a/Source/Engine/Graphics/Textures/TextureBase.cpp +++ b/Source/Engine/Graphics/Textures/TextureBase.cpp @@ -13,6 +13,7 @@ #include "Engine/Content/Factories/BinaryAssetFactory.h" #include "Engine/Graphics/PixelFormatSampler.h" #include "Engine/Scripting/Enums.h" +#include "Engine/Streaming/Streaming.h" #include "Engine/Tools/TextureTool/TextureTool.h" #include "Engine/Threading/Threading.h" #if GPU_ENABLE_RESOURCE_NAMING && !USE_EDITOR @@ -706,6 +707,9 @@ bool TextureBase::Init(InitData* initData) return true; } + // Speed up update texture uplaod to GPU by alocating texture async task now to run before next frame rendering + Streaming::UpdateResource(&_texture); + return false; } diff --git a/Source/Engine/Graphics/Textures/TextureBase.h b/Source/Engine/Graphics/Textures/TextureBase.h index 930078157..8bd2668f2 100644 --- a/Source/Engine/Graphics/Textures/TextureBase.h +++ b/Source/Engine/Graphics/Textures/TextureBase.h @@ -25,17 +25,17 @@ API_CLASS(Abstract, NoSpawn) class FLAXENGINE_API TextureBase : public BinaryAss struct MipData { BytesContainer Data; - uint32 RowPitch; - uint32 SlicePitch; + uint32 RowPitch = 0; + uint32 SlicePitch = 0; MipData() = default; MipData(MipData&& other) noexcept; }; - PixelFormat Format; - int32 Width; - int32 Height; - int32 ArraySize; + PixelFormat Format = PixelFormat::Unknown; + int32 Width = 0; + int32 Height = 0; + int32 ArraySize = 1; Array> Mips; InitData() = default; diff --git a/Source/Engine/Streaming/Streaming.cpp b/Source/Engine/Streaming/Streaming.cpp index 5ddbd0996..c3b2ed542 100644 --- a/Source/Engine/Streaming/Streaming.cpp +++ b/Source/Engine/Streaming/Streaming.cpp @@ -115,8 +115,6 @@ void StreamableResource::StopStreaming() void UpdateResource(StreamableResource* resource, double currentTime) { - ASSERT(resource && resource->CanBeUpdated()); - // Pick group and handler dedicated for that resource auto group = resource->GetGroup(); auto handler = group->GetHandler(); @@ -328,3 +326,13 @@ GPUSampler* Streaming::GetTextureGroupSampler(int32 index) } return sampler; } + +void Streaming::UpdateResource(StreamableResource* resource) +{ + if (!resource || !resource->CanBeUpdated()) + return; + PROFILE_MEM(ContentStreaming); + ScopeLock lock(ResourcesLock); + const double currentTime = Platform::GetTimeSeconds(); + ::UpdateResource(resource, currentTime); +} diff --git a/Source/Engine/Streaming/Streaming.h b/Source/Engine/Streaming/Streaming.h index 9b906ae75..c76b7a2dc 100644 --- a/Source/Engine/Streaming/Streaming.h +++ b/Source/Engine/Streaming/Streaming.h @@ -7,6 +7,7 @@ #include "TextureGroup.h" class GPUSampler; +class StreamableResource; // Streaming service statistics container. API_STRUCT(NoDefault) struct FLAXENGINE_API StreamingStats @@ -46,4 +47,10 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Streaming); /// The texture group index. /// The texture sampler (always valid). API_FUNCTION() static GPUSampler* GetTextureGroupSampler(int32 index); + + /// + /// Manually updates a specific resource (calculates capacity and spawns streaming in/out async tasks). Usefull to force stream speciifc resource without delay or waiting for the next streaming update. + /// + /// The resource to update (eg. texture or mesh). + static void UpdateResource(StreamableResource* resource); };