Add additional UploadMipMapAsync for GPUTexture update with custom row/slice pitch

This commit is contained in:
Wojciech Figat
2022-02-08 18:04:44 +01:00
committed by Wojtek Figat
parent 3c9a5bcf1a
commit 066a4c65bb
6 changed files with 46 additions and 24 deletions

View File

@@ -16,7 +16,7 @@ class GPUUploadTextureMipTask : public GPUTask
protected: protected:
GPUTextureReference _texture; GPUTextureReference _texture;
int32 _mipIndex; int32 _mipIndex, _rowPitch, _slicePitch;
BytesContainer _data; BytesContainer _data;
public: public:
@@ -27,11 +27,15 @@ public:
/// <param name="texture">The target texture.</param> /// <param name="texture">The target texture.</param>
/// <param name="mipIndex">The target texture mip data.</param> /// <param name="mipIndex">The target texture mip data.</param>
/// <param name="data">The data to upload.</param> /// <param name="data">The data to upload.</param>
/// <param name="rowPitch">The data row pitch.</param>
/// <param name="slicePitch">The data slice pitch.</param>
/// <param name="copyData">True if copy data to the temporary buffer, otherwise the input data will be used directly. Then ensure it is valid during the copy operation period (for the next few frames).</param> /// <param name="copyData">True if copy data to the temporary buffer, otherwise the input data will be used directly. Then ensure it is valid during the copy operation period (for the next few frames).</param>
GPUUploadTextureMipTask(GPUTexture* texture, int32 mipIndex, Span<byte> data, bool copyData) GPUUploadTextureMipTask(GPUTexture* texture, int32 mipIndex, Span<byte> data, int32 rowPitch, int32 slicePitch, bool copyData)
: GPUTask(Type::UploadTexture) : GPUTask(Type::UploadTexture)
, _texture(texture) , _texture(texture)
, _mipIndex(mipIndex) , _mipIndex(mipIndex)
, _rowPitch(rowPitch)
, _slicePitch(slicePitch)
{ {
_texture.OnUnload.Bind<GPUUploadTextureMipTask, &GPUUploadTextureMipTask::OnResourceUnload>(this); _texture.OnUnload.Bind<GPUUploadTextureMipTask, &GPUUploadTextureMipTask::OnResourceUnload>(this);
@@ -66,18 +70,14 @@ protected:
return Result::MissingResources; return Result::MissingResources;
ASSERT(texture->IsAllocated()); ASSERT(texture->IsAllocated());
// Cache data
const int32 arraySize = texture->ArraySize();
uint32 rowPitch, slicePitch;
texture->ComputePitch(_mipIndex, rowPitch, slicePitch);
ASSERT((uint32)_data.Length() >= slicePitch * arraySize);
// Update all array slices // Update all array slices
const byte* dataSource = _data.Get(); const byte* dataSource = _data.Get();
const int32 arraySize = texture->ArraySize();
ASSERT(_data.Length() >= _slicePitch * arraySize);
for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++) for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
{ {
context->GPU->UpdateTexture(texture, arrayIndex, _mipIndex, dataSource, rowPitch, slicePitch); context->GPU->UpdateTexture(texture, arrayIndex, _mipIndex, dataSource, _rowPitch, _slicePitch);
dataSource += slicePitch; dataSource += _slicePitch;
} }
return Result::Ok; return Result::Ok;

View File

@@ -595,17 +595,21 @@ void GPUTexture::OnReleaseGPU()
_residentMipLevels = 0; _residentMipLevels = 0;
} }
GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex) GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, bool copyData)
{ {
ASSERT(IsRegularTexture() && IsAllocated()); uint32 rowPitch, slicePitch;
//ASSERT(Math::IsInRange(mipIndex, HighestResidentMipIndex() - 1, MipLevels() - 1) && mipIndex < MipLevels() && data.IsValid()); ComputePitch(mipIndex, rowPitch, slicePitch);
return UploadMipMapAsync(data, mipIndex, rowPitch, slicePitch, copyData);
}
GPUTask* GPUTexture::UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData)
{
ASSERT(IsAllocated());
ASSERT(mipIndex < MipLevels() && data.IsValid()); ASSERT(mipIndex < MipLevels() && data.IsValid());
ASSERT(data.Length() == SlicePitch(mipIndex) * ArraySize()); ASSERT(data.Length() >= slicePitch);
// TODO: support texture data upload to the GPU on a main thread during rendering without this async task (faster direct upload)
// Create task auto task = ::New<GPUUploadTextureMipTask>(this, mipIndex, data, rowPitch, slicePitch, copyData);
auto task = ::New<GPUUploadTextureMipTask>(this, mipIndex, data, false); ASSERT_LOW_LAYER(task && task->HasReference(this));
ASSERT(task && task->HasReference(this));
return task; return task;
} }

View File

@@ -524,8 +524,20 @@ public:
/// </summary> /// </summary>
/// <param name="data">Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing)</param> /// <param name="data">Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing)</param>
/// <param name="mipIndex">Mip level index.</param> /// <param name="mipIndex">Mip level index.</param>
/// <param name="copyData">If true, the data will be copied to the async execution task instead of using the input pointer provided.</param>
/// <returns>Created async task or null if cannot.</returns> /// <returns>Created async task or null if cannot.</returns>
GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex); GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, bool copyData = false);
/// <summary>
/// Uploads mip map data to the GPU. Creates async GPU task.
/// </summary>
/// <param name="data">Data to upload (it must be valid for the next a few frames due to GPU latency and async works executing)</param>
/// <param name="mipIndex">Mip level index.</param>
/// <param name="rowPitch">The data row pitch.</param>
/// <param name="slicePitch">The data slice pitch.</param>
/// <param name="copyData">If true, the data will be copied to the async execution task instead of using the input pointer provided.</param>
/// <returns>Created async task or null if cannot.</returns>
GPUTask* UploadMipMapAsync(const BytesContainer& data, int32 mipIndex, int32 rowPitch, int32 slicePitch, bool copyData = false);
/// <summary> /// <summary>
/// Stops current thread execution to gather texture data from the GPU. /// Stops current thread execution to gather texture data from the GPU.

View File

@@ -316,7 +316,7 @@ private:
public: public:
StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex) StreamTextureMipTask(StreamingTexture* texture, int32 mipIndex)
: GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), false) : GPUUploadTextureMipTask(texture->GetTexture(), mipIndex, Span<byte>(nullptr, 0), 0, 0, false)
, _streamingTexture(texture) , _streamingTexture(texture)
, _dataLock(_streamingTexture->GetOwner()->LockData()) , _dataLock(_streamingTexture->GetOwner()->LockData())
{ {

View File

@@ -210,7 +210,9 @@ void FontTextureAtlas::Flush()
// Upload data to the GPU // Upload data to the GPU
BytesContainer data; BytesContainer data;
data.Link(_data); data.Link(_data);
_texture->UploadMipMapAsync(data, 0)->Start(); auto task = _texture->UploadMipMapAsync(data, 0);
if (task)
task->Start();
// Clear dirty flag // Clear dirty flag
_isDirty = false; _isDirty = false;

View File

@@ -1627,7 +1627,9 @@ bool TerrainPatch::ModifySplatMap(int32 index, const Color32* samples, const Int
LOG(Warning, "Failed to update splatmap texture. It's not allocated."); LOG(Warning, "Failed to update splatmap texture. It's not allocated.");
continue; continue;
} }
t->UploadMipMapAsync(dataSplatmap->Mips[mipIndex].Data, mipIndex)->Start(); auto task = t->UploadMipMapAsync(dataSplatmap->Mips[mipIndex].Data, mipIndex);
if (task)
task->Start();
} }
} }
else else
@@ -1745,7 +1747,9 @@ bool TerrainPatch::UpdateHeightData(const TerrainDataUpdateInfo& info, const Int
// Update terrain texture (on a GPU) // Update terrain texture (on a GPU)
for (int32 mipIndex = 0; mipIndex < _dataHeightmap->Mips.Count(); mipIndex++) for (int32 mipIndex = 0; mipIndex < _dataHeightmap->Mips.Count(); mipIndex++)
{ {
texture->UploadMipMapAsync(_dataHeightmap->Mips[mipIndex].Data, mipIndex)->Start(); auto task = texture->UploadMipMapAsync(_dataHeightmap->Mips[mipIndex].Data, mipIndex);
if (task)
task->Start();
} }
#if 1 #if 1