Optimize Texture::DownloadData for staging textures

This commit is contained in:
Wojtek Figat
2021-02-07 20:06:44 +01:00
parent 8c1f56b7db
commit 5768eefe49

View File

@@ -458,43 +458,13 @@ protected:
// [ThreadPoolTask]
bool Run() override
{
// Check resources
auto texture = _texture.Get();
if (texture == nullptr || _staging == nullptr || _data == nullptr)
{
LOG(Warning, "Cannot download texture data. Missing objects.");
return true;
}
const auto arraySize = texture->ArraySize();
const auto mipLevels = texture->MipLevels();
// Get all mip maps for each array slice
auto& rawResultData = _data->Items;
rawResultData.Resize(arraySize, false);
for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
{
auto& arraySlice = rawResultData[arrayIndex];
arraySlice.Mips.Resize(mipLevels);
for (int32 mipMapIndex = 0; mipMapIndex < mipLevels; mipMapIndex++)
{
auto& mip = arraySlice.Mips[mipMapIndex];
const int32 mipWidth = _data->Width >> mipMapIndex;
const int32 mipHeight = _data->Height >> mipMapIndex;
uint32 mipRowPitch, mipSlicePitch;
RenderTools::ComputePitch(_data->Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch);
// Gather data
if (_staging->GetData(arrayIndex, mipMapIndex, mip, mipRowPitch))
{
LOG(Warning, "Staging resource of \'{0}\' get data failed.", texture->ToString());
return true;
}
}
}
return false;
return _staging->DownloadData(*_data);
}
void OnEnd() override
@@ -508,6 +478,57 @@ protected:
bool GPUTexture::DownloadData(TextureData& result)
{
// Skip for empty ones
if (MipLevels() == 0)
{
LOG(Warning, "Cannot download GPU texture data from an empty texture.");
return true;
}
if (Depth() != 1)
{
MISSING_CODE("support volume texture data downloading.");
}
// Use faster path for staging resources
if (IsStaging())
{
const auto arraySize = ArraySize();
const auto mipLevels = MipLevels();
// Set texture info
result.Width = Width();
result.Height = Height();
result.Depth = Depth();
result.Format = Format();
// Get all mip maps for each array slice
auto& rawResultData = result.Items;
rawResultData.Resize(arraySize, false);
for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
{
auto& arraySlice = rawResultData[arrayIndex];
arraySlice.Mips.Resize(mipLevels);
for (int32 mipMapIndex = 0; mipMapIndex < mipLevels; mipMapIndex++)
{
auto& mip = arraySlice.Mips[mipMapIndex];
const int32 mipWidth = result.Width >> mipMapIndex;
const int32 mipHeight = result.Height >> mipMapIndex;
uint32 mipRowPitch, mipSlicePitch;
RenderTools::ComputePitch(result.Format, mipWidth, mipHeight, mipRowPitch, mipSlicePitch);
// Gather data
if (GetData(arrayIndex, mipMapIndex, mip, mipRowPitch))
{
LOG(Warning, "Staging resource of \'{0}\' get data failed.", ToString());
return true;
}
}
}
return false;
}
const auto name = ToString();
// Ensure not running on main thread - we support DownloadData from textures only on a worker threads (Thread Pool Workers or Content Loaders)
@@ -538,7 +559,8 @@ bool GPUTexture::DownloadData(TextureData& result)
Task* GPUTexture::DownloadDataAsync(TextureData& result)
{
if (!IsAllocated())
// Skip for empty ones
if (MipLevels() == 0)
{
LOG(Warning, "Cannot download texture data. It has not ben created yet.");
return nullptr;
@@ -548,19 +570,12 @@ Task* GPUTexture::DownloadDataAsync(TextureData& result)
MISSING_CODE("support volume texture data downloading.");
}
// Set texture info
result.Width = Width();
result.Height = Height();
result.Depth = Depth();
result.Format = Format();
// Quicker path if texture is already readback
if (_desc.Usage == GPUResourceUsage::StagingReadback)
// Use faster path for staging resources
if (IsStaging())
{
// Create task to copy downloaded data to TextureData container
auto getDataTask = ::New<TextureDownloadDataTask>(this, this, result);
ASSERT(getDataTask->HasReference(this));
return getDataTask;
}