diff --git a/renderdoc/api/replay/data_types.h b/renderdoc/api/replay/data_types.h index b765c8dfc..75b4e0a06 100644 --- a/renderdoc/api/replay/data_types.h +++ b/renderdoc/api/replay/data_types.h @@ -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; } diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index 17b6cf6d7..26543967f 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -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) { diff --git a/renderdoc/core/replay_proxy.cpp b/renderdoc/core/replay_proxy.cpp index 2c522c028..04910f525 100644 --- a/renderdoc/core/replay_proxy.cpp +++ b/renderdoc/core/replay_proxy.cpp @@ -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); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 6a28f9eb6..4734c79a8 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -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) diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 9daa54995..ef3c37846 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -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; diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index f885185a2..2ff35be02 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -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) diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index d215447e8..59f06f557 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -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); diff --git a/renderdoc/driver/vulkan/vk_resources.cpp b/renderdoc/driver/vulkan/vk_resources.cpp index 8355e2278..25bf83261 100644 --- a/renderdoc/driver/vulkan/vk_resources.cpp +++ b/renderdoc/driver/vulkan/vk_resources.cpp @@ -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; diff --git a/renderdoc/maths/formatpacking.cpp b/renderdoc/maths/formatpacking.cpp index 572694770..d5e9630b9 100644 --- a/renderdoc/maths/formatpacking.cpp +++ b/renderdoc/maths/formatpacking.cpp @@ -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); } diff --git a/renderdoc/maths/formatpacking.h b/renderdoc/maths/formatpacking.h index 41531b1a4..bffb488d1 100644 --- a/renderdoc/maths/formatpacking.h +++ b/renderdoc/maths/formatpacking.h @@ -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); diff --git a/renderdoc/replay/replay_controller.cpp b/renderdoc/replay/replay_controller.cpp index 4b0155b37..408d354d4 100644 --- a/renderdoc/replay/replay_controller.cpp +++ b/renderdoc/replay/replay_controller.cpp @@ -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; diff --git a/renderdoc/replay/replay_driver.cpp b/renderdoc/replay/replay_driver.cpp index ff2bc4043..5d6c33d5b 100644 --- a/renderdoc/replay/replay_driver.cpp +++ b/renderdoc/replay/replay_driver.cpp @@ -43,6 +43,7 @@ template void DoSerialise(SerialiserType &ser, GetTextureDataParams &el) { SERIALISE_MEMBER(forDiskSave); + SERIALISE_MEMBER(standardLayout); SERIALISE_MEMBER(typeCast); SERIALISE_MEMBER(resolve); SERIALISE_MEMBER(remap); diff --git a/renderdoc/replay/replay_driver.h b/renderdoc/replay/replay_driver.h index 5deddc66b..d97cb96c4 100644 --- a/renderdoc/replay/replay_driver.h +++ b/renderdoc/replay/replay_driver.h @@ -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; diff --git a/util/test/demos/gl/gl_texture_zoo.cpp b/util/test/demos/gl/gl_texture_zoo.cpp index 31f6cd640..0a340d4e9 100644 --- a/util/test/demos/gl/gl_texture_zoo.cpp +++ b/util/test/demos/gl/gl_texture_zoo.cpp @@ -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; diff --git a/util/test/demos/texture_zoo.cpp b/util/test/demos/texture_zoo.cpp index 4d04f04ed..e12b5600f 100644 --- a/util/test/demos/texture_zoo.cpp +++ b/util/test/demos/texture_zoo.cpp @@ -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) { diff --git a/util/test/demos/vk/vk_texture_zoo.cpp b/util/test/demos/vk/vk_texture_zoo.cpp index 92a2fd451..3c9cadbaf 100644 --- a/util/test/demos/vk/vk_texture_zoo.cpp +++ b/util/test/demos/vk/vk_texture_zoo.cpp @@ -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: diff --git a/util/test/rdtest/shared/Texture_Zoo.py b/util/test/rdtest/shared/Texture_Zoo.py index 507a139d2..6165ae10e 100644 --- a/util/test/rdtest/shared/Texture_Zoo.py +++ b/util/test/rdtest/shared/Texture_Zoo.py @@ -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