mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-07-18 13:37:11 +00:00
Save .rdc file extthumbnail as PNG
In order to embed the original rendered image during the capture in its original form, without incurring JPEG pixel artifacts, use PNG file format for thumbnails. Change-Id: I14ff487856949cd6f83889507e16feb4c50a40fb
This commit is contained in:
committed by
Baldur Karlsson
parent
3233afd390
commit
264b296b7d
+149
-15
@@ -29,9 +29,11 @@
|
||||
#include "api/replay/version.h"
|
||||
#include "common/common.h"
|
||||
#include "hooks/hooks.h"
|
||||
#include "maths/formatpacking.h"
|
||||
#include "replay/replay_driver.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
#include "serialise/serialiser.h"
|
||||
#include "stb/stb_image_write.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "crash_handler.h"
|
||||
|
||||
@@ -716,8 +718,142 @@ bool RenderDoc::ShouldTriggerCapture(uint32_t frameNumber)
|
||||
return ret;
|
||||
}
|
||||
|
||||
RDCFile *RenderDoc::CreateRDC(RDCDriver driver, uint32_t frameNum, void *thpixels, size_t thlen,
|
||||
uint16_t thwidth, uint16_t thheight, FileType thformat)
|
||||
void RenderDoc::ResamplePixels(const FramePixels &in, RDCThumb &out)
|
||||
{
|
||||
// code below assumes pitch_requirement is a power of 2 number
|
||||
RDCASSERT((in.pitch_requirement & (in.pitch_requirement - 1)) == 0);
|
||||
|
||||
out.width = (uint16_t)RDCMIN(in.max_width, in.width);
|
||||
out.width &= ~(in.pitch_requirement - 1); // align down to multiple of in.
|
||||
out.height = uint16_t(out.width * in.height / in.width);
|
||||
out.len = 3 * out.width * out.height;
|
||||
out.pixels = new byte[out.len];
|
||||
out.format = FileType::Raw;
|
||||
|
||||
byte *dst = (byte *)out.pixels;
|
||||
byte *source = (byte *)in.data;
|
||||
|
||||
for(uint32_t y = 0; y < out.height; y++)
|
||||
{
|
||||
for(uint32_t x = 0; x < out.width; x++)
|
||||
{
|
||||
uint32_t xSource = x * in.width / out.width;
|
||||
uint32_t ySource = y * in.height / out.height;
|
||||
byte *src = &source[in.stride * xSource + in.pitch * ySource];
|
||||
|
||||
if(in.buf1010102)
|
||||
{
|
||||
uint32_t *src1010102 = (uint32_t *)src;
|
||||
Vec4f unorm = ConvertFromR10G10B10A2(*src1010102);
|
||||
dst[0] = (byte)(unorm.x * 255.0f);
|
||||
dst[1] = (byte)(unorm.y * 255.0f);
|
||||
dst[2] = (byte)(unorm.z * 255.0f);
|
||||
}
|
||||
else if(in.buf565)
|
||||
{
|
||||
uint16_t *src565 = (uint16_t *)src;
|
||||
Vec3f unorm = ConvertFromB5G6R5(*src565);
|
||||
dst[0] = (byte)(unorm.z * 255.0f);
|
||||
dst[1] = (byte)(unorm.y * 255.0f);
|
||||
dst[2] = (byte)(unorm.x * 255.0f);
|
||||
}
|
||||
else if(in.buf5551)
|
||||
{
|
||||
uint16_t *src5551 = (uint16_t *)src;
|
||||
Vec4f unorm = ConvertFromB5G5R5A1(*src5551);
|
||||
dst[0] = (byte)(unorm.z * 255.0f);
|
||||
dst[1] = (byte)(unorm.y * 255.0f);
|
||||
dst[2] = (byte)(unorm.x * 255.0f);
|
||||
}
|
||||
else if(in.bgra)
|
||||
{
|
||||
dst[0] = src[2];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[0];
|
||||
}
|
||||
else if(in.bpc == 2) // R16G16B16A16 backbuffer
|
||||
{
|
||||
uint16_t *src16 = (uint16_t *)src;
|
||||
|
||||
float linearR = RDCCLAMP(ConvertFromHalf(src16[0]), 0.0f, 1.0f);
|
||||
float linearG = RDCCLAMP(ConvertFromHalf(src16[1]), 0.0f, 1.0f);
|
||||
float linearB = RDCCLAMP(ConvertFromHalf(src16[2]), 0.0f, 1.0f);
|
||||
|
||||
if(linearR < 0.0031308f)
|
||||
dst[0] = byte(255.0f * (12.92f * linearR));
|
||||
else
|
||||
dst[0] = byte(255.0f * (1.055f * powf(linearR, 1.0f / 2.4f) - 0.055f));
|
||||
|
||||
if(linearG < 0.0031308f)
|
||||
dst[1] = byte(255.0f * (12.92f * linearG));
|
||||
else
|
||||
dst[1] = byte(255.0f * (1.055f * powf(linearG, 1.0f / 2.4f) - 0.055f));
|
||||
|
||||
if(linearB < 0.0031308f)
|
||||
dst[2] = byte(255.0f * (12.92f * linearB));
|
||||
else
|
||||
dst[2] = byte(255.0f * (1.055f * powf(linearB, 1.0f / 2.4f) - 0.055f));
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[0] = src[0];
|
||||
dst[1] = src[1];
|
||||
dst[2] = src[2];
|
||||
}
|
||||
dst += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(!in.is_y_flipped)
|
||||
{
|
||||
for(uint16_t y = 0; y <= out.height / 2; y++)
|
||||
{
|
||||
uint16_t flipY = (out.height - 1 - y);
|
||||
for(uint16_t x = 0; x < out.width; x++)
|
||||
{
|
||||
byte *src = (byte *)out.pixels;
|
||||
byte save[3];
|
||||
save[0] = src[(y * out.width + x) * 3 + 0];
|
||||
save[1] = src[(y * out.width + x) * 3 + 1];
|
||||
save[2] = src[(y * out.width + x) * 3 + 2];
|
||||
|
||||
src[(y * out.width + x) * 3 + 0] = src[(flipY * out.width + x) * 3 + 0];
|
||||
src[(y * out.width + x) * 3 + 1] = src[(flipY * out.width + x) * 3 + 1];
|
||||
src[(y * out.width + x) * 3 + 2] = src[(flipY * out.width + x) * 3 + 2];
|
||||
|
||||
src[(flipY * out.width + x) * 3 + 0] = save[0];
|
||||
src[(flipY * out.width + x) * 3 + 1] = save[1];
|
||||
src[(flipY * out.width + x) * 3 + 2] = save[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void RenderDoc::EncodePixelsPNG(const RDCThumb &in, RDCThumb &out)
|
||||
{
|
||||
struct WriteCallbackData
|
||||
{
|
||||
std::vector<byte> buffer;
|
||||
|
||||
static void writeData(void *context, void *data, int size)
|
||||
{
|
||||
WriteCallbackData *pThis = (WriteCallbackData *)context;
|
||||
const byte *start = (const byte *)data;
|
||||
pThis->buffer.insert(pThis->buffer.end(), start, start + size);
|
||||
}
|
||||
};
|
||||
|
||||
WriteCallbackData callbackData;
|
||||
stbi_write_png_to_func(&WriteCallbackData::writeData, &callbackData, in.width, in.height, 3,
|
||||
in.pixels, 0);
|
||||
out.width = in.width;
|
||||
out.height = in.height;
|
||||
out.pixels = new byte[callbackData.buffer.size()];
|
||||
memcpy((void *)out.pixels, callbackData.buffer.data(), callbackData.buffer.size());
|
||||
out.len = (uint32_t)callbackData.buffer.size();
|
||||
out.format = FileType::PNG;
|
||||
}
|
||||
|
||||
RDCFile *RenderDoc::CreateRDC(RDCDriver driver, uint32_t frameNum, const FramePixels &fp)
|
||||
{
|
||||
RDCFile *ret = new RDCFile;
|
||||
|
||||
@@ -737,22 +873,17 @@ RDCFile *RenderDoc::CreateRDC(RDCDriver driver, uint32_t frameNum, void *thpixel
|
||||
}
|
||||
}
|
||||
|
||||
RDCThumb th;
|
||||
RDCThumb *thumb = NULL;
|
||||
|
||||
if(thpixels)
|
||||
RDCThumb outRaw, outPng;
|
||||
if(fp.data)
|
||||
{
|
||||
th.len = (uint32_t)thlen;
|
||||
th.pixels = (const byte *)thpixels;
|
||||
th.width = thwidth;
|
||||
th.height = thheight;
|
||||
RDCASSERT(thformat == FileType::JPG || thformat == FileType::PNG || thformat == FileType::BMP ||
|
||||
thformat == FileType::TGA || thformat == FileType::Raw);
|
||||
th.format = thformat;
|
||||
thumb = &th;
|
||||
// point sample info into raw buffer
|
||||
ResamplePixels(fp, outRaw);
|
||||
EncodePixelsPNG(outRaw, outPng);
|
||||
}
|
||||
|
||||
ret->SetData(driver, ToStr(driver).c_str(), OSUtility::GetMachineIdent(), thumb);
|
||||
RDCASSERT(outPng.pixels != NULL);
|
||||
|
||||
ret->SetData(driver, ToStr(driver).c_str(), OSUtility::GetMachineIdent(), &outPng);
|
||||
|
||||
FileIO::CreateParentDirectory(m_CurrentLogFile);
|
||||
|
||||
@@ -764,6 +895,9 @@ RDCFile *RenderDoc::CreateRDC(RDCDriver driver, uint32_t frameNum, void *thpixel
|
||||
SAFE_DELETE(ret);
|
||||
}
|
||||
|
||||
SAFE_DELETE_ARRAY(outRaw.pixels);
|
||||
SAFE_DELETE_ARRAY(outPng.pixels);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user