|
|
|
|
@ -21,6 +21,8 @@
|
|
|
|
|
#include <Atom/Utils/PpmFile.h>
|
|
|
|
|
|
|
|
|
|
#include <AtomCore/Serialization/Json/JsonUtils.h>
|
|
|
|
|
#include <AzCore/Jobs/JobFunction.h>
|
|
|
|
|
#include <AzCore/Jobs/JobCompletion.h>
|
|
|
|
|
|
|
|
|
|
#include <AzCore/IO/SystemFile.h>
|
|
|
|
|
#include <AzCore/RTTI/BehaviorContext.h>
|
|
|
|
|
@ -55,6 +57,43 @@ namespace AZ
|
|
|
|
|
FrameCaptureOutputResult PngFrameCaptureOutput(
|
|
|
|
|
const AZStd::string& outputFilePath, const AZ::RPI::AttachmentReadback::ReadbackResult& readbackResult)
|
|
|
|
|
{
|
|
|
|
|
AZStd::shared_ptr<AZStd::vector<uint8_t>> buffer = readbackResult.m_dataBuffer;
|
|
|
|
|
|
|
|
|
|
// convert bgra to rgba by swapping channels
|
|
|
|
|
const int numChannels = AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format);
|
|
|
|
|
if (readbackResult.m_imageDescriptor.m_format == RHI::Format::B8G8R8A8_UNORM)
|
|
|
|
|
{
|
|
|
|
|
buffer = AZStd::make_shared<AZStd::vector<uint8_t>>(readbackResult.m_dataBuffer->size());
|
|
|
|
|
AZStd::copy(readbackResult.m_dataBuffer->begin(), readbackResult.m_dataBuffer->end(), buffer->begin());
|
|
|
|
|
|
|
|
|
|
AZ::JobCompletion jobCompletion;
|
|
|
|
|
const int numThreads = 8;
|
|
|
|
|
const int numPixelsPerThread = buffer->size() / numChannels / numThreads;
|
|
|
|
|
for (int i = 0; i < numThreads; ++i)
|
|
|
|
|
{
|
|
|
|
|
int startPixel = i * numPixelsPerThread;
|
|
|
|
|
|
|
|
|
|
AZ::Job* job = AZ::CreateJobFunction(
|
|
|
|
|
[&, startPixel, numPixelsPerThread]()
|
|
|
|
|
{
|
|
|
|
|
for (int pixelOffset = 0; pixelOffset < numPixelsPerThread; ++pixelOffset)
|
|
|
|
|
{
|
|
|
|
|
if (startPixel * numChannels + numChannels < buffer->size())
|
|
|
|
|
{
|
|
|
|
|
AZStd::swap(
|
|
|
|
|
buffer->data()[(startPixel + pixelOffset) * numChannels],
|
|
|
|
|
buffer->data()[(startPixel + pixelOffset) * numChannels + 2]
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}, true, nullptr);
|
|
|
|
|
|
|
|
|
|
job->SetDependent(&jobCompletion);
|
|
|
|
|
job->Start();
|
|
|
|
|
}
|
|
|
|
|
jobCompletion.StartAndWaitForCompletion();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using namespace OIIO;
|
|
|
|
|
AZStd::unique_ptr<ImageOutput> out = ImageOutput::create(outputFilePath.c_str());
|
|
|
|
|
if (out)
|
|
|
|
|
@ -62,13 +101,13 @@ namespace AZ
|
|
|
|
|
ImageSpec spec(
|
|
|
|
|
readbackResult.m_imageDescriptor.m_size.m_width,
|
|
|
|
|
readbackResult.m_imageDescriptor.m_size.m_height,
|
|
|
|
|
AZ::RHI::GetFormatComponentCount(readbackResult.m_imageDescriptor.m_format)
|
|
|
|
|
numChannels
|
|
|
|
|
);
|
|
|
|
|
spec.attribute("png:compressionLevel", r_pngCompressionLevel);
|
|
|
|
|
|
|
|
|
|
if (out->open(outputFilePath.c_str(), spec))
|
|
|
|
|
{
|
|
|
|
|
out->write_image(TypeDesc::UINT8, readbackResult.m_dataBuffer->data());
|
|
|
|
|
out->write_image(TypeDesc::UINT8, buffer->data());
|
|
|
|
|
out->close();
|
|
|
|
|
return FrameCaptureOutputResult{FrameCaptureResult::Success, AZStd::nullopt};
|
|
|
|
|
}
|
|
|
|
|
@ -460,13 +499,23 @@ namespace AZ
|
|
|
|
|
#if defined(OPEN_IMAGE_IO_ENABLED)
|
|
|
|
|
else if (extension == "png")
|
|
|
|
|
{
|
|
|
|
|
AZStd::string folderPath;
|
|
|
|
|
AzFramework::StringFunc::Path::GetFolderPath(m_outputFilePath.c_str(), folderPath);
|
|
|
|
|
AZ::IO::SystemFile::CreateDir(folderPath.c_str());
|
|
|
|
|
if (readbackResult.m_imageDescriptor.m_format == RHI::Format::R8G8B8A8_UNORM ||
|
|
|
|
|
readbackResult.m_imageDescriptor.m_format == RHI::Format::B8G8R8A8_UNORM)
|
|
|
|
|
{
|
|
|
|
|
AZStd::string folderPath;
|
|
|
|
|
AzFramework::StringFunc::Path::GetFolderPath(m_outputFilePath.c_str(), folderPath);
|
|
|
|
|
AZ::IO::SystemFile::CreateDir(folderPath.c_str());
|
|
|
|
|
|
|
|
|
|
const auto frameCaptureResult = PngFrameCaptureOutput(m_outputFilePath, readbackResult);
|
|
|
|
|
m_result = frameCaptureResult.m_result;
|
|
|
|
|
m_latestCaptureInfo = frameCaptureResult.m_errorMessage.value_or("");
|
|
|
|
|
const auto frameCaptureResult = PngFrameCaptureOutput(m_outputFilePath, readbackResult);
|
|
|
|
|
m_result = frameCaptureResult.m_result;
|
|
|
|
|
m_latestCaptureInfo = frameCaptureResult.m_errorMessage.value_or("");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_latestCaptureInfo = AZStd::string::format(
|
|
|
|
|
"Can't save image with format %s to a png file", RHI::ToString(readbackResult.m_imageDescriptor.m_format));
|
|
|
|
|
m_result = FrameCaptureResult::UnsupportedFormat;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
else
|
|
|
|
|
|