mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-29 13:20:54 +00:00
Standardise layout of packed texture formats on disk/network
* We preserve each API's interpretation of bit order for packed formats like RGBA4 or R5G6B5 when displaying the raw data in the UI, but when we need to proxy it or save to disk, we always transform to D3D's order as standard. * This allows us to proxy them reliably because we always have a standard bit order and APIs that need a different order transform when fetching data to the standard format, or setting proxy data from the standard format.
This commit is contained in:
@@ -203,6 +203,14 @@ struct ResourceFormat
|
||||
)");
|
||||
|
||||
DOCUMENT(R"(:return: ``True`` if the components are to be read in ``BGRA`` order.
|
||||
|
||||
.. note::
|
||||
The convention is that components are in RGBA order. Whether that means first byte to last byte,
|
||||
or in bit-packed formats red in the lowest bits.
|
||||
|
||||
With BGRA order this means blue is in the first byte/lowest bits, but alpha is still always
|
||||
expected in the last byte/uppermost bits.
|
||||
|
||||
:rtype: ``bool``
|
||||
)");
|
||||
bool BGRAOrder() const { return (flags & ResourceFormat_BGRA) != 0; }
|
||||
|
||||
@@ -1029,17 +1029,17 @@ void RenderDoc::ResamplePixels(const FramePixels &in, RDCThumb &out)
|
||||
{
|
||||
uint16_t *src565 = (uint16_t *)src;
|
||||
Vec3f unorm = ConvertFromB5G6R5(*src565);
|
||||
dst[0] = (byte)(unorm.z * 255.0f);
|
||||
dst[0] = (byte)(unorm.x * 255.0f);
|
||||
dst[1] = (byte)(unorm.y * 255.0f);
|
||||
dst[2] = (byte)(unorm.x * 255.0f);
|
||||
dst[2] = (byte)(unorm.z * 255.0f);
|
||||
}
|
||||
else if(in.buf5551)
|
||||
{
|
||||
uint16_t *src5551 = (uint16_t *)src;
|
||||
Vec4f unorm = ConvertFromB5G5R5A1(*src5551);
|
||||
dst[0] = (byte)(unorm.z * 255.0f);
|
||||
dst[0] = (byte)(unorm.x * 255.0f);
|
||||
dst[1] = (byte)(unorm.y * 255.0f);
|
||||
dst[2] = (byte)(unorm.x * 255.0f);
|
||||
dst[2] = (byte)(unorm.z * 255.0f);
|
||||
}
|
||||
else if(in.bgra)
|
||||
{
|
||||
|
||||
@@ -2389,6 +2389,7 @@ void ReplayProxy::EnsureTexCached(ResourceId &texid, CompType &typeCast, const S
|
||||
GetTextureDataParams params = proxy.params;
|
||||
|
||||
params.typeCast = typeCast;
|
||||
params.standardLayout = true;
|
||||
|
||||
#if ENABLED(TRANSFER_RESOURCE_CONTENTS_DELTAS)
|
||||
CacheTextureData(texid, s, params);
|
||||
|
||||
@@ -3641,16 +3641,6 @@ void D3D11Replay::SetProxyTextureData(ResourceId texid, const Subresource &sub,
|
||||
|
||||
bool D3D11Replay::IsTextureSupported(const TextureDescription &tex)
|
||||
{
|
||||
// these formats are inconsistently laid out between APIs, always remap
|
||||
switch(tex.format.type)
|
||||
{
|
||||
case ResourceFormatType::R4G4:
|
||||
case ResourceFormatType::R4G4B4A4:
|
||||
case ResourceFormatType::R5G6B5:
|
||||
case ResourceFormatType::R5G5B5A1: return false;
|
||||
default: break;
|
||||
}
|
||||
|
||||
DXGI_FORMAT f = MakeDXGIFormat(tex.format);
|
||||
|
||||
if(f == DXGI_FORMAT_UNKNOWN)
|
||||
|
||||
@@ -2039,11 +2039,13 @@ ResourceFormat MakeResourceFormat(GLenum target, GLenum fmt)
|
||||
ret.type = ResourceFormatType::R5G6B5;
|
||||
ret.compType = CompType::UNorm;
|
||||
ret.compCount = 3;
|
||||
ret.SetBGRAOrder(true);
|
||||
break;
|
||||
case eGL_RGB5_A1:
|
||||
ret.type = ResourceFormatType::R5G5B5A1;
|
||||
ret.compType = CompType::UNorm;
|
||||
ret.compCount = 4;
|
||||
ret.SetBGRAOrder(true);
|
||||
break;
|
||||
case eGL_RGB9_E5:
|
||||
ret.type = ResourceFormatType::R9G9B9E5;
|
||||
@@ -2054,6 +2056,7 @@ ResourceFormat MakeResourceFormat(GLenum target, GLenum fmt)
|
||||
ret.type = ResourceFormatType::R4G4B4A4;
|
||||
ret.compType = CompType::UNorm;
|
||||
ret.compCount = 4;
|
||||
ret.SetBGRAOrder(true);
|
||||
break;
|
||||
case eGL_RGB10_A2:
|
||||
case eGL_RGB10_A2UI:
|
||||
@@ -2268,10 +2271,25 @@ GLenum MakeGLFormat(ResourceFormat fmt)
|
||||
ret = eGL_RGB10_A2UI;
|
||||
break;
|
||||
case ResourceFormatType::R11G11B10: ret = eGL_R11F_G11F_B10F; break;
|
||||
case ResourceFormatType::R5G6B5: ret = eGL_RGB565; break;
|
||||
case ResourceFormatType::R5G5B5A1: ret = eGL_RGB5_A1; break;
|
||||
case ResourceFormatType::R5G6B5:
|
||||
// only support bgra order
|
||||
if(fmt.BGRAOrder())
|
||||
return eGL_RGB565;
|
||||
else
|
||||
return eGL_NONE;
|
||||
case ResourceFormatType::R5G5B5A1:
|
||||
// only support bgra order
|
||||
if(fmt.BGRAOrder())
|
||||
return eGL_RGB5_A1;
|
||||
else
|
||||
return eGL_NONE;
|
||||
case ResourceFormatType::R9G9B9E5: ret = eGL_RGB9_E5; break;
|
||||
case ResourceFormatType::R4G4B4A4: ret = eGL_RGBA4; break;
|
||||
case ResourceFormatType::R4G4B4A4:
|
||||
// only support bgra order
|
||||
if(fmt.BGRAOrder())
|
||||
return eGL_RGBA4;
|
||||
else
|
||||
return eGL_NONE;
|
||||
case ResourceFormatType::D24S8: ret = eGL_DEPTH24_STENCIL8; break;
|
||||
case ResourceFormatType::D32S8: ret = eGL_DEPTH32F_STENCIL8; break;
|
||||
case ResourceFormatType::D16S8: return eGL_NONE;
|
||||
|
||||
@@ -2319,7 +2319,11 @@ void GLReplay::GetTextureData(ResourceId tex, const Subresource &sub,
|
||||
else if(params.remap == RemapTexture::RGBA32)
|
||||
remapFormat = eGL_RGBA32F;
|
||||
|
||||
remapFormat = GetViewCastedFormat(remapFormat, BaseRemapType(params.typeCast));
|
||||
CompType typeCast = params.typeCast;
|
||||
if(typeCast == CompType::Typeless && IsSRGBFormat(intFormat))
|
||||
typeCast = CompType::UNormSRGB;
|
||||
|
||||
remapFormat = GetViewCastedFormat(remapFormat, BaseRemapType(typeCast));
|
||||
|
||||
if(intFormat != remapFormat)
|
||||
{
|
||||
@@ -2723,19 +2727,50 @@ void GLReplay::GetTextureData(ResourceId tex, const Subresource &sub,
|
||||
drv.glGetTexImage(target, (GLint)s.mip, fmt, type, data.data());
|
||||
}
|
||||
|
||||
// GL puts D24 in the top bits (whether or not there's stencil). We choose to standardise it
|
||||
// to be in the low bits, so swizzle here. for D24 with no stencil, the stencil bits are
|
||||
// undefined so we can move them around and it means nothing.
|
||||
if(intFormat == eGL_DEPTH24_STENCIL8 || intFormat == eGL_DEPTH_COMPONENT24)
|
||||
if(params.standardLayout)
|
||||
{
|
||||
uint32_t *ptr = (uint32_t *)data.data();
|
||||
|
||||
for(GLsizei y = 0; y < height; y++)
|
||||
// GL puts D24 in the top bits (whether or not there's stencil). We choose to standardise it
|
||||
// to be in the low bits, so swizzle here. for D24 with no stencil, the stencil bits are
|
||||
// undefined so we can move them around and it means nothing.
|
||||
if(intFormat == eGL_DEPTH24_STENCIL8 || intFormat == eGL_DEPTH_COMPONENT24)
|
||||
{
|
||||
for(GLsizei x = 0; x < width; x++)
|
||||
uint32_t *ptr = (uint32_t *)data.data();
|
||||
|
||||
for(GLsizei z = 0; z < depth; z++)
|
||||
{
|
||||
const uint32_t val = *ptr;
|
||||
*ptr = (val >> 8) | ((val & 0xff) << 24);
|
||||
for(GLsizei y = 0; y < height; y++)
|
||||
{
|
||||
for(GLsizei x = 0; x < width; x++)
|
||||
{
|
||||
const uint32_t val = *ptr;
|
||||
*ptr = (val >> 8) | ((val & 0xff) << 24);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GL's RGBA4/RGB5A1 is BGRA order, but it puts alpha in the bottom bits where we expect it
|
||||
// in the top
|
||||
if(intFormat == eGL_RGBA4)
|
||||
{
|
||||
uint16_t *ptr = (uint16_t *)data.data();
|
||||
|
||||
for(size_t i = 0; i < data.size(); i += sizeof(uint16_t))
|
||||
{
|
||||
const uint16_t val = *ptr;
|
||||
*ptr = (val >> 4) | ((val & 0xf) << 12);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if(intFormat == eGL_RGB5_A1)
|
||||
{
|
||||
uint16_t *ptr = (uint16_t *)data.data();
|
||||
|
||||
for(size_t i = 0; i < data.size(); i += sizeof(uint16_t))
|
||||
{
|
||||
const uint16_t val = *ptr;
|
||||
*ptr = (val >> 1) | ((val & 0x1) << 15);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
@@ -3246,6 +3281,40 @@ void GLReplay::SetProxyTextureData(ResourceId texid, const Subresource &sub, byt
|
||||
|
||||
data = swizzled.data();
|
||||
}
|
||||
// GL's RGBA4/RGB5A1 is BGRA order, but it puts alpha in the bottom bits where we expect it
|
||||
// in the top
|
||||
else if(texdetails.internalFormat == eGL_RGBA4)
|
||||
{
|
||||
const uint16_t *srcptr = (const uint16_t *)data;
|
||||
swizzled.resize(dataSize);
|
||||
uint16_t *dstptr = (uint16_t *)swizzled.data();
|
||||
|
||||
for(size_t i = 0; i < dataSize; i += 2)
|
||||
{
|
||||
const uint16_t val = *srcptr;
|
||||
*dstptr = ((val & 0x0fff) << 4) | ((val & 0xf000) >> 12);
|
||||
srcptr++;
|
||||
dstptr++;
|
||||
}
|
||||
|
||||
data = swizzled.data();
|
||||
}
|
||||
else if(texdetails.internalFormat == eGL_RGB5_A1)
|
||||
{
|
||||
const uint16_t *srcptr = (const uint16_t *)data;
|
||||
swizzled.resize(dataSize);
|
||||
uint16_t *dstptr = (uint16_t *)swizzled.data();
|
||||
|
||||
for(size_t i = 0; i < dataSize; i += 2)
|
||||
{
|
||||
const uint16_t val = *srcptr;
|
||||
*dstptr = ((val & 0x7fff) << 1) | ((val & 0x8000) >> 12);
|
||||
srcptr++;
|
||||
dstptr++;
|
||||
}
|
||||
|
||||
data = swizzled.data();
|
||||
}
|
||||
|
||||
if(target == eGL_TEXTURE_1D)
|
||||
{
|
||||
@@ -3312,8 +3381,13 @@ void GLReplay::SetProxyTextureData(ResourceId texid, const Subresource &sub, byt
|
||||
|
||||
bool GLReplay::IsTextureSupported(const TextureDescription &tex)
|
||||
{
|
||||
// these formats are inconsistently laid out between APIs, always remap if the remote API is
|
||||
// different
|
||||
// GL can't decide if these formats are BGRA or RGBA order.
|
||||
// The bit order in memory for e.g. R4G4B4A4 is:
|
||||
// 15 .. .. 0
|
||||
// R G B A
|
||||
//
|
||||
// but if you upload bits in that order with GL_RGBA it gets flipped.
|
||||
// It's more reliable to report no support and force a remap
|
||||
switch(tex.format.type)
|
||||
{
|
||||
case ResourceFormatType::R4G4:
|
||||
@@ -3332,11 +3406,6 @@ bool GLReplay::IsTextureSupported(const TextureDescription &tex)
|
||||
if(tex.format.type == ResourceFormatType::A8)
|
||||
return false;
|
||||
|
||||
// BGRA is not accepted as an internal format in case of GL
|
||||
// EXT_texture_format_BGRA8888 is required for creating BGRA proxy textures in case of GLES
|
||||
if(tex.format.BGRAOrder())
|
||||
return IsGLES && HasExt[EXT_texture_format_BGRA8888];
|
||||
|
||||
// don't support 1D/3D block compressed textures
|
||||
if(tex.dimension != 2 &&
|
||||
(tex.format.type == ResourceFormatType::BC1 || tex.format.type == ResourceFormatType::BC2 ||
|
||||
@@ -3357,6 +3426,11 @@ bool GLReplay::IsTextureSupported(const TextureDescription &tex)
|
||||
if(fmt == eGL_NONE)
|
||||
return false;
|
||||
|
||||
// BGRA is not accepted as an internal format in case of GL
|
||||
// EXT_texture_format_BGRA8888 is required for creating BGRA proxy textures in case of GLES
|
||||
if(fmt == eGL_BGRA8_EXT && (!IsGLES || !HasExt[EXT_texture_format_BGRA8888]))
|
||||
return false;
|
||||
|
||||
GLenum target = eGL_TEXTURE_2D;
|
||||
|
||||
switch(tex.type)
|
||||
|
||||
@@ -3628,6 +3628,36 @@ void VulkanReplay::GetTextureData(ResourceId tex, const Subresource &sub,
|
||||
else
|
||||
{
|
||||
memcpy(data.data(), pData, dataSize);
|
||||
|
||||
// vulkan's bitpacking of some layouts puts alpha in the low bits, which is not our 'standard'
|
||||
// layout and is not representable in our resource formats
|
||||
if(params.standardLayout)
|
||||
{
|
||||
if(imCreateInfo.format == VK_FORMAT_R4G4B4A4_UNORM_PACK16 ||
|
||||
imCreateInfo.format == VK_FORMAT_B4G4R4A4_UNORM_PACK16)
|
||||
{
|
||||
uint16_t *ptr = (uint16_t *)data.data();
|
||||
|
||||
for(uint32_t i = 0; i < dataSize; i += sizeof(uint16_t))
|
||||
{
|
||||
const uint16_t val = *ptr;
|
||||
*ptr = (val >> 4) | ((val & 0xf) << 12);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else if(imCreateInfo.format == VK_FORMAT_R5G5B5A1_UNORM_PACK16 ||
|
||||
imCreateInfo.format == VK_FORMAT_B5G5R5A1_UNORM_PACK16)
|
||||
{
|
||||
uint16_t *ptr = (uint16_t *)data.data();
|
||||
|
||||
for(uint32_t i = 0; i < dataSize; i += sizeof(uint16_t))
|
||||
{
|
||||
const uint16_t val = *ptr;
|
||||
*ptr = (val >> 1) | ((val & 0x1) << 15);
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vt->UnmapMemory(Unwrap(dev), readbackMem);
|
||||
|
||||
@@ -1811,9 +1811,10 @@ ResourceFormat MakeResourceFormat(VkFormat fmt)
|
||||
|
||||
switch(fmt)
|
||||
{
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16:
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
||||
case VK_FORMAT_B8G8R8A8_UNORM:
|
||||
case VK_FORMAT_B8G8R8A8_SNORM:
|
||||
case VK_FORMAT_B8G8R8A8_USCALED:
|
||||
@@ -2710,14 +2711,14 @@ VkFormat MakeVkFormat(ResourceFormat fmt)
|
||||
break;
|
||||
case ResourceFormatType::R11G11B10: ret = VK_FORMAT_B10G11R11_UFLOAT_PACK32; break;
|
||||
case ResourceFormatType::R5G6B5:
|
||||
ret = fmt.BGRAOrder() ? VK_FORMAT_B5G6R5_UNORM_PACK16 : VK_FORMAT_R5G6B5_UNORM_PACK16;
|
||||
ret = fmt.BGRAOrder() ? VK_FORMAT_R5G6B5_UNORM_PACK16 : VK_FORMAT_B5G6R5_UNORM_PACK16;
|
||||
break;
|
||||
case ResourceFormatType::R5G5B5A1:
|
||||
ret = fmt.BGRAOrder() ? VK_FORMAT_B5G5R5A1_UNORM_PACK16 : VK_FORMAT_R5G5B5A1_UNORM_PACK16;
|
||||
ret = fmt.BGRAOrder() ? VK_FORMAT_R5G5B5A1_UNORM_PACK16 : VK_FORMAT_B5G5R5A1_UNORM_PACK16;
|
||||
break;
|
||||
case ResourceFormatType::R9G9B9E5: ret = VK_FORMAT_E5B9G9R9_UFLOAT_PACK32; break;
|
||||
case ResourceFormatType::R4G4B4A4:
|
||||
ret = fmt.BGRAOrder() ? VK_FORMAT_B4G4R4A4_UNORM_PACK16 : VK_FORMAT_R4G4B4A4_UNORM_PACK16;
|
||||
ret = fmt.BGRAOrder() ? VK_FORMAT_R4G4B4A4_UNORM_PACK16 : VK_FORMAT_B4G4R4A4_UNORM_PACK16;
|
||||
break;
|
||||
case ResourceFormatType::R4G4: ret = VK_FORMAT_R4G4_UNORM_PACK8; break;
|
||||
case ResourceFormatType::D16S8: ret = VK_FORMAT_D16_UNORM_S8_UINT; break;
|
||||
|
||||
@@ -301,6 +301,9 @@ FloatVector ConvertComponents(const ResourceFormat &fmt, const byte *data)
|
||||
ret.y = v.y;
|
||||
ret.z = v.z;
|
||||
ret.w = v.w;
|
||||
|
||||
if(fmt.BGRAOrder())
|
||||
std::swap(ret.x, ret.z);
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R11G11B10)
|
||||
{
|
||||
@@ -312,25 +315,46 @@ FloatVector ConvertComponents(const ResourceFormat &fmt, const byte *data)
|
||||
else if(fmt.type == ResourceFormatType::R5G5B5A1)
|
||||
{
|
||||
Vec4f v = ConvertFromB5G5R5A1(*(const uint16_t *)data);
|
||||
ret.x = v.z;
|
||||
ret.x = v.x;
|
||||
ret.y = v.y;
|
||||
ret.z = v.x;
|
||||
ret.z = v.z;
|
||||
ret.w = v.w;
|
||||
|
||||
// conversely we *expect* BGRA order for this format and the above conversion implicitly flips
|
||||
// when bit-unpacking. So if the format wasn't BGRA order, flip it back
|
||||
if(!fmt.BGRAOrder())
|
||||
std::swap(ret.x, ret.z);
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R5G6B5)
|
||||
{
|
||||
Vec3f v = ConvertFromB5G6R5(*(const uint16_t *)data);
|
||||
ret.x = v.z;
|
||||
ret.x = v.x;
|
||||
ret.y = v.y;
|
||||
ret.z = v.x;
|
||||
ret.z = v.z;
|
||||
|
||||
// conversely we *expect* BGRA order for this format and the above conversion implicitly flips
|
||||
// when bit-unpacking. So if the format wasn't BGRA order, flip it back
|
||||
if(!fmt.BGRAOrder())
|
||||
std::swap(ret.x, ret.z);
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R4G4B4A4)
|
||||
{
|
||||
Vec4f v = ConvertFromB4G4R4A4(*(const uint16_t *)data);
|
||||
ret.x = v.z;
|
||||
ret.x = v.x;
|
||||
ret.y = v.y;
|
||||
ret.z = v.x;
|
||||
ret.z = v.z;
|
||||
ret.w = v.w;
|
||||
|
||||
// conversely we *expect* BGRA order for this format and the above conversion implicitly flips
|
||||
// when bit-unpacking. So if the format wasn't BGRA order, flip it back
|
||||
if(!fmt.BGRAOrder())
|
||||
std::swap(ret.x, ret.z);
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R4G4)
|
||||
{
|
||||
Vec4f v = ConvertFromR4G4(*(const uint8_t *)data);
|
||||
ret.x = v.x;
|
||||
ret.y = v.y;
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::R9G9B9E5)
|
||||
{
|
||||
@@ -338,9 +362,35 @@ FloatVector ConvertComponents(const ResourceFormat &fmt, const byte *data)
|
||||
ret.x = v.x;
|
||||
ret.y = v.y;
|
||||
ret.z = v.z;
|
||||
RDCLOG("%x -> %f,%f,%f", *(const uint32_t *)data, v.x, v.y, v.z);
|
||||
}
|
||||
else
|
||||
else if(fmt.type == ResourceFormatType::D16S8)
|
||||
{
|
||||
uint32_t val = *(const uint32_t *)data;
|
||||
ret.x = float(val & 0x00ffff) / 65535.0f;
|
||||
ret.y = float((val & 0xff0000) >> 16) / 255.0f;
|
||||
ret.z = 0.0f;
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::D24S8)
|
||||
{
|
||||
uint32_t val = *(const uint32_t *)data;
|
||||
ret.x = float(val & 0x00ffffff) / 16777215.0f;
|
||||
ret.y = float((val & 0xff000000) >> 24) / 255.0f;
|
||||
ret.z = 0.0f;
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::D32S8)
|
||||
{
|
||||
struct ds
|
||||
{
|
||||
float f;
|
||||
uint32_t s;
|
||||
} val;
|
||||
val = *(const ds *)data;
|
||||
ret.x = val.f;
|
||||
ret.y = float(val.s) / 255.0f;
|
||||
ret.z = 0.0f;
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::Regular || fmt.type == ResourceFormatType::A8 ||
|
||||
fmt.type == ResourceFormatType::S8)
|
||||
{
|
||||
float *comp = &ret.x;
|
||||
|
||||
@@ -394,9 +444,9 @@ FloatVector ConvertComponents(const ResourceFormat &fmt, const byte *data)
|
||||
const uint8_t *u8 = (const uint8_t *)data;
|
||||
|
||||
uint32_t depth = 0;
|
||||
depth |= uint32_t(u8[1]);
|
||||
depth |= uint32_t(u8[2]) << 8;
|
||||
depth |= uint32_t(u8[3]) << 16;
|
||||
depth |= uint32_t(u8[0]);
|
||||
depth |= uint32_t(u8[1]) << 8;
|
||||
depth |= uint32_t(u8[2]) << 16;
|
||||
|
||||
*comp = float(depth) / float(16777215.0f);
|
||||
}
|
||||
@@ -476,6 +526,17 @@ FloatVector ConvertComponents(const ResourceFormat &fmt, const byte *data)
|
||||
data += fmt.compByteWidth;
|
||||
}
|
||||
|
||||
if(fmt.type == ResourceFormatType::A8)
|
||||
{
|
||||
ret.w = ret.x;
|
||||
ret.x = 0.0f;
|
||||
}
|
||||
else if(fmt.type == ResourceFormatType::S8)
|
||||
{
|
||||
ret.y = ret.x;
|
||||
ret.x = 0.0f;
|
||||
}
|
||||
|
||||
if(fmt.BGRAOrder())
|
||||
std::swap(ret.x, ret.z);
|
||||
}
|
||||
|
||||
@@ -79,20 +79,25 @@ uint32_t ConvertToR11G11B10(Vec3f data);
|
||||
|
||||
inline Vec4f ConvertFromB5G5R5A1(uint16_t data)
|
||||
{
|
||||
return Vec4f((float)((data >> 0) & 0x1f) / 31.0f, (float)((data >> 5) & 0x1f) / 31.0f,
|
||||
(float)((data >> 10) & 0x1f) / 31.0f, ((data & 0x8000) > 0) ? 1.0f : 0.0f);
|
||||
return Vec4f((float)((data >> 10) & 0x1f) / 31.0f, (float)((data >> 5) & 0x1f) / 31.0f,
|
||||
(float)((data >> 0) & 0x1f) / 31.0f, ((data & 0x8000) > 0) ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
inline Vec3f ConvertFromB5G6R5(uint16_t data)
|
||||
{
|
||||
return Vec3f((float)((data >> 0) & 0x1f) / 31.0f, (float)((data >> 5) & 0x3f) / 63.0f,
|
||||
(float)((data >> 11) & 0x1f) / 31.0f);
|
||||
return Vec3f((float)((data >> 11) & 0x1f) / 31.0f, (float)((data >> 5) & 0x3f) / 63.0f,
|
||||
(float)((data >> 0) & 0x1f) / 31.0f);
|
||||
}
|
||||
|
||||
inline Vec4f ConvertFromB4G4R4A4(uint16_t data)
|
||||
{
|
||||
return Vec4f((float)((data >> 0) & 0xf) / 15.0f, (float)((data >> 4) & 0xf) / 15.0f,
|
||||
(float)((data >> 8) & 0xf) / 15.0f, (float)((data >> 12) & 0xf) / 15.0f);
|
||||
return Vec4f((float)((data >> 8) & 0xf) / 15.0f, (float)((data >> 4) & 0xf) / 15.0f,
|
||||
(float)((data >> 0) & 0xf) / 15.0f, (float)((data >> 12) & 0xf) / 15.0f);
|
||||
}
|
||||
|
||||
inline Vec4f ConvertFromR4G4(uint8_t data)
|
||||
{
|
||||
return Vec4f((float)((data >> 0) & 0xf) / 15.0f, (float)((data >> 4) & 0xf) / 15.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
Vec3f ConvertFromR9G9B9E5(uint32_t data);
|
||||
|
||||
@@ -847,6 +847,7 @@ bool ReplayController::SaveTexture(const TextureSave &saveData, const char *path
|
||||
|
||||
GetTextureDataParams params;
|
||||
params.forDiskSave = true;
|
||||
params.standardLayout = true;
|
||||
params.typeCast = sd.typeCast;
|
||||
params.resolve = resolveSamples;
|
||||
params.remap = remap;
|
||||
|
||||
@@ -43,6 +43,7 @@ template <typename SerialiserType>
|
||||
void DoSerialise(SerialiserType &ser, GetTextureDataParams &el)
|
||||
{
|
||||
SERIALISE_MEMBER(forDiskSave);
|
||||
SERIALISE_MEMBER(standardLayout);
|
||||
SERIALISE_MEMBER(typeCast);
|
||||
SERIALISE_MEMBER(resolve);
|
||||
SERIALISE_MEMBER(remap);
|
||||
|
||||
@@ -83,7 +83,15 @@ DECLARE_REFLECTION_ENUM(RemapTexture);
|
||||
|
||||
struct GetTextureDataParams
|
||||
{
|
||||
// this data is going to be saved to disk, so prepare it as needed. E.g. on GL flip Y order to
|
||||
// match conventional axis for file formats.
|
||||
bool forDiskSave = false;
|
||||
// this data is going to be transferred cross-API e.g. in replay proxying, so standardise bit
|
||||
// layout of any packed formats where API conventions differ (mostly only RGBA4 or other awkward
|
||||
// ones where our resource formats don't enumerate all possible iterations). Saving to disk is
|
||||
// also standardised to ensure the data matches any format description we also write to the
|
||||
// format.
|
||||
bool standardLayout = false;
|
||||
CompType typeCast = CompType::Typeless;
|
||||
bool resolve = false;
|
||||
RemapTexture remap = RemapTexture::NoRemap;
|
||||
|
||||
@@ -848,11 +848,16 @@ void main()
|
||||
t.hasData = true;
|
||||
|
||||
bool srgb = false;
|
||||
bool bgr = false;
|
||||
switch(t.fmt.internalFormat)
|
||||
{
|
||||
// only need to handle renderable SRGB formats here
|
||||
case GL_SRGB8:
|
||||
case GL_SRGB8_ALPHA8: srgb = true; break;
|
||||
case GL_BGRA8_EXT:
|
||||
case GL_RGBA4:
|
||||
case GL_RGB5_A1:
|
||||
case GL_RGB565: bgr = true;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -862,6 +867,8 @@ void main()
|
||||
flags |= 1;
|
||||
if(srgb)
|
||||
flags |= 2;
|
||||
if(bgr)
|
||||
flags |= 4;
|
||||
|
||||
GLuint slices = t.isArray ? texSlices : 1u;
|
||||
GLuint mips = t.isMSAA || t.isRect ? 1u : texMips;
|
||||
|
||||
@@ -189,7 +189,7 @@ void MakeData(TexData &data, const TexConfig &cfg, Vec4i dimensions, uint32_t mi
|
||||
case TextureType::BC7: bc7 = true; break;
|
||||
case TextureType::R9G9B9E5: sharedExp = true; break;
|
||||
case TextureType::G4R4: nybblePattern = 0x12; break;
|
||||
case TextureType::A4R4G4B4: nybblePattern = 0x1234; break;
|
||||
case TextureType::A4R4G4B4: nybblePattern = 0x3214; break;
|
||||
case TextureType::R4G4B4A4: nybblePattern = 0x4321; break;
|
||||
case TextureType::R5G6B5:
|
||||
rgb5 = true;
|
||||
@@ -302,15 +302,15 @@ void MakeData(TexData &data, const TexConfig &cfg, Vec4i dimensions, uint32_t mi
|
||||
|
||||
if(alphabitPlace == 0)
|
||||
{
|
||||
encodedPixel |= uint16_t(rgb[2] * 31) << 0;
|
||||
encodedPixel |= uint16_t(rgb[0] * 31) << 0;
|
||||
encodedPixel |= uint16_t(rgb[1] * 63) << 5;
|
||||
encodedPixel |= uint16_t(rgb[0] * 31) << 11;
|
||||
encodedPixel |= uint16_t(rgb[2] * 31) << 11;
|
||||
}
|
||||
else
|
||||
{
|
||||
encodedPixel |= uint16_t(rgb[2] * 31) << 0;
|
||||
encodedPixel |= uint16_t(rgb[0] * 31) << 0;
|
||||
encodedPixel |= uint16_t(rgb[1] * 31) << 5;
|
||||
encodedPixel |= uint16_t(rgb[0] * 31) << 10;
|
||||
encodedPixel |= uint16_t(rgb[2] * 31) << 10;
|
||||
|
||||
if(alphabitPlace == 1)
|
||||
{
|
||||
|
||||
@@ -1172,9 +1172,10 @@ void main()
|
||||
bool srgb = false, bgra = false;
|
||||
switch(t.fmt.viewFmt)
|
||||
{
|
||||
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_B5G6R5_UNORM_PACK16:
|
||||
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
|
||||
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G6B5_UNORM_PACK16:
|
||||
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
|
||||
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
|
||||
case VK_FORMAT_B8G8R8_UNORM:
|
||||
case VK_FORMAT_B8G8R8_SNORM:
|
||||
case VK_FORMAT_B8G8R8_USCALED:
|
||||
|
||||
@@ -15,7 +15,9 @@ class Texture_Zoo():
|
||||
self.textures = {}
|
||||
self.controller: rd.ReplayController
|
||||
self.controller = None
|
||||
self.pipeType = rd.GraphicsAPI.D3D11
|
||||
self.opengl_mode = False
|
||||
self.d3d_mode = False
|
||||
|
||||
def sub(self, mip: int, slice: int, sample: int):
|
||||
if self.fake_msaa:
|
||||
@@ -70,6 +72,9 @@ class Texture_Zoo():
|
||||
success: bool = self.controller.SaveTexture(save_data, path)
|
||||
|
||||
if not success:
|
||||
if self.d3d_mode:
|
||||
raise rdtest.TestFailureException("Couldn't save DDS to {} on D3D.".format(self.filename))
|
||||
|
||||
try:
|
||||
os.remove(path)
|
||||
except Exception:
|
||||
@@ -369,7 +374,9 @@ class Texture_Zoo():
|
||||
def check_capture(self, capture_filename: str, controller: rd.ReplayController):
|
||||
self.controller = controller
|
||||
|
||||
self.pipeType = self.controller.GetAPIProperties().pipelineType
|
||||
self.opengl_mode = (self.controller.GetAPIProperties().pipelineType == rd.GraphicsAPI.OpenGL)
|
||||
self.d3d_mode = rd.IsD3D(self.controller.GetAPIProperties().pipelineType)
|
||||
|
||||
failed = False
|
||||
|
||||
@@ -442,11 +449,6 @@ class Texture_Zoo():
|
||||
ret: Tuple[rd.ReplayStatus, rd.ReplayController] = cap.OpenCapture(rd.ReplayOptions(), None)
|
||||
status, self.controller = ret
|
||||
|
||||
# Some packed formats can't be opened, allow that
|
||||
if status == rd.ReplayStatus.ImageUnsupported and 'dds' in file.name:
|
||||
rdtest.log.print("Couldn't open {} - unsupported".format(file.name))
|
||||
continue
|
||||
|
||||
if status != rd.ReplayStatus.Succeeded:
|
||||
rdtest.log.error("Couldn't open {}".format(file.name))
|
||||
failed = True
|
||||
|
||||
Reference in New Issue
Block a user