diff --git a/renderdoc/Makefile b/renderdoc/Makefile index 7939a352c..f308d35f6 100644 --- a/renderdoc/Makefile +++ b/renderdoc/Makefile @@ -17,6 +17,7 @@ hooks/hooks.o \ hooks/gl_linux_hooks.o \ serialise/serialiser.o \ common/common.o \ +common/dds_readwrite.o \ core/remote_access.o \ core/replay_proxy.o \ core/remote_replay.o \ diff --git a/renderdoc/common/dds_readwrite.cpp b/renderdoc/common/dds_readwrite.cpp new file mode 100644 index 000000000..b44e0691f --- /dev/null +++ b/renderdoc/common/dds_readwrite.cpp @@ -0,0 +1,607 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "common/common.h" +#include + +#include "dds_readwrite.h" + +// from MSDN +struct DDS_PIXELFORMAT { + uint32_t dwSize; + uint32_t dwFlags; + uint32_t dwFourCC; + uint32_t dwRGBBitCount; + uint32_t dwRBitMask; + uint32_t dwGBitMask; + uint32_t dwBBitMask; + uint32_t dwABitMask; +}; + +struct DDS_HEADER { + uint32_t dwSize; + uint32_t dwFlags; + uint32_t dwHeight; + uint32_t dwWidth; + uint32_t dwPitchOrLinearSize; + uint32_t dwDepth; + uint32_t dwMipMapCount; + uint32_t dwReserved1[11]; + DDS_PIXELFORMAT ddspf; + uint32_t dwCaps; + uint32_t dwCaps2; + uint32_t dwCaps3; + uint32_t dwCaps4; + uint32_t dwReserved2; +}; + +// from d3d10.h +enum D3D10_RESOURCE_DIMENSION +{ + D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D10_RESOURCE_DIMENSION_BUFFER = 1, + D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4 +}; + +// from dxgiformat.h +enum DXGI_FORMAT +{ + DXGI_FORMAT_UNKNOWN = 0, + DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, + DXGI_FORMAT_R32G32B32A32_FLOAT = 2, + DXGI_FORMAT_R32G32B32A32_UINT = 3, + DXGI_FORMAT_R32G32B32A32_SINT = 4, + DXGI_FORMAT_R32G32B32_TYPELESS = 5, + DXGI_FORMAT_R32G32B32_FLOAT = 6, + DXGI_FORMAT_R32G32B32_UINT = 7, + DXGI_FORMAT_R32G32B32_SINT = 8, + DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, + DXGI_FORMAT_R16G16B16A16_FLOAT = 10, + DXGI_FORMAT_R16G16B16A16_UNORM = 11, + DXGI_FORMAT_R16G16B16A16_UINT = 12, + DXGI_FORMAT_R16G16B16A16_SNORM = 13, + DXGI_FORMAT_R16G16B16A16_SINT = 14, + DXGI_FORMAT_R32G32_TYPELESS = 15, + DXGI_FORMAT_R32G32_FLOAT = 16, + DXGI_FORMAT_R32G32_UINT = 17, + DXGI_FORMAT_R32G32_SINT = 18, + DXGI_FORMAT_R32G8X24_TYPELESS = 19, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, + DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, + DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, + DXGI_FORMAT_R10G10B10A2_UNORM = 24, + DXGI_FORMAT_R10G10B10A2_UINT = 25, + DXGI_FORMAT_R11G11B10_FLOAT = 26, + DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, + DXGI_FORMAT_R8G8B8A8_UNORM = 28, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, + DXGI_FORMAT_R8G8B8A8_UINT = 30, + DXGI_FORMAT_R8G8B8A8_SNORM = 31, + DXGI_FORMAT_R8G8B8A8_SINT = 32, + DXGI_FORMAT_R16G16_TYPELESS = 33, + DXGI_FORMAT_R16G16_FLOAT = 34, + DXGI_FORMAT_R16G16_UNORM = 35, + DXGI_FORMAT_R16G16_UINT = 36, + DXGI_FORMAT_R16G16_SNORM = 37, + DXGI_FORMAT_R16G16_SINT = 38, + DXGI_FORMAT_R32_TYPELESS = 39, + DXGI_FORMAT_D32_FLOAT = 40, + DXGI_FORMAT_R32_FLOAT = 41, + DXGI_FORMAT_R32_UINT = 42, + DXGI_FORMAT_R32_SINT = 43, + DXGI_FORMAT_R24G8_TYPELESS = 44, + DXGI_FORMAT_D24_UNORM_S8_UINT = 45, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, + DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, + DXGI_FORMAT_R8G8_TYPELESS = 48, + DXGI_FORMAT_R8G8_UNORM = 49, + DXGI_FORMAT_R8G8_UINT = 50, + DXGI_FORMAT_R8G8_SNORM = 51, + DXGI_FORMAT_R8G8_SINT = 52, + DXGI_FORMAT_R16_TYPELESS = 53, + DXGI_FORMAT_R16_FLOAT = 54, + DXGI_FORMAT_D16_UNORM = 55, + DXGI_FORMAT_R16_UNORM = 56, + DXGI_FORMAT_R16_UINT = 57, + DXGI_FORMAT_R16_SNORM = 58, + DXGI_FORMAT_R16_SINT = 59, + DXGI_FORMAT_R8_TYPELESS = 60, + DXGI_FORMAT_R8_UNORM = 61, + DXGI_FORMAT_R8_UINT = 62, + DXGI_FORMAT_R8_SNORM = 63, + DXGI_FORMAT_R8_SINT = 64, + DXGI_FORMAT_A8_UNORM = 65, + DXGI_FORMAT_R1_UNORM = 66, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, + DXGI_FORMAT_R8G8_B8G8_UNORM = 68, + DXGI_FORMAT_G8R8_G8B8_UNORM = 69, + DXGI_FORMAT_BC1_TYPELESS = 70, + DXGI_FORMAT_BC1_UNORM = 71, + DXGI_FORMAT_BC1_UNORM_SRGB = 72, + DXGI_FORMAT_BC2_TYPELESS = 73, + DXGI_FORMAT_BC2_UNORM = 74, + DXGI_FORMAT_BC2_UNORM_SRGB = 75, + DXGI_FORMAT_BC3_TYPELESS = 76, + DXGI_FORMAT_BC3_UNORM = 77, + DXGI_FORMAT_BC3_UNORM_SRGB = 78, + DXGI_FORMAT_BC4_TYPELESS = 79, + DXGI_FORMAT_BC4_UNORM = 80, + DXGI_FORMAT_BC4_SNORM = 81, + DXGI_FORMAT_BC5_TYPELESS = 82, + DXGI_FORMAT_BC5_UNORM = 83, + DXGI_FORMAT_BC5_SNORM = 84, + DXGI_FORMAT_B5G6R5_UNORM = 85, + DXGI_FORMAT_B5G5R5A1_UNORM = 86, + DXGI_FORMAT_B8G8R8A8_UNORM = 87, + DXGI_FORMAT_B8G8R8X8_UNORM = 88, + DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, + DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, + DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, + DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, + DXGI_FORMAT_BC6H_TYPELESS = 94, + DXGI_FORMAT_BC6H_UF16 = 95, + DXGI_FORMAT_BC6H_SF16 = 96, + DXGI_FORMAT_BC7_TYPELESS = 97, + DXGI_FORMAT_BC7_UNORM = 98, + DXGI_FORMAT_BC7_UNORM_SRGB = 99, + DXGI_FORMAT_AYUV = 100, + DXGI_FORMAT_Y410 = 101, + DXGI_FORMAT_Y416 = 102, + DXGI_FORMAT_NV12 = 103, + DXGI_FORMAT_P010 = 104, + DXGI_FORMAT_P016 = 105, + DXGI_FORMAT_420_OPAQUE = 106, + DXGI_FORMAT_YUY2 = 107, + DXGI_FORMAT_Y210 = 108, + DXGI_FORMAT_Y216 = 109, + DXGI_FORMAT_NV11 = 110, + DXGI_FORMAT_AI44 = 111, + DXGI_FORMAT_IA44 = 112, + DXGI_FORMAT_P8 = 113, + DXGI_FORMAT_A8P8 = 114, + DXGI_FORMAT_B4G4R4A4_UNORM = 115, + DXGI_FORMAT_FORCE_UINT = 0xffffffff +}; + +struct DDS_HEADER_DXT10 { + DXGI_FORMAT dxgiFormat; + D3D10_RESOURCE_DIMENSION resourceDimension; + uint32_t miscFlag; + uint32_t arraySize; + uint32_t reserved; +}; + +#define DDSD_CAPS 0x1 +#define DDSD_HEIGHT 0x2 +#define DDSD_WIDTH 0x4 +#define DDSD_PITCH 0x8 +#define DDSD_PIXELFORMAT 0x1000 +#define DDSD_MIPMAPCOUNT 0x20000 +#define DDSD_LINEARSIZE 0x80000 +#define DDSD_DEPTH 0x800000 + +#define DDSCAPS_COMPLEX 0x8 +#define DDSCAPS_MIPMAP 0x400000 +#define DDSCAPS_TEXTURE 0x1000 + +#define DDSCAPS2_CUBEMAP 0xff00 // d3d10+ requires all cubemap faces +#define DDSCAPS2_VOLUME 0x200000 + +#define DDS_RESOURCE_MISC_TEXTURECUBE 0x4 + +#define DDPF_ALPHAPIXELS 0x1 +#define DDPF_ALPHA 0x2 +#define DDPF_FOURCC 0x4 +#define DDPF_RGB 0x40 +#define DDPF_YUV 0x200 +#define DDPF_LUMINANCE 0x20000 +#define DDPF_RGBA (DDPF_RGB|DDPF_ALPHAPIXELS) + +DXGI_FORMAT ResourceFormat2DXGIFormat(ResourceFormat format) +{ + if(format.special) + { + switch(format.specialFormat) + { + case eSpecial_BC1: + return format.srgbCorrected ? DXGI_FORMAT_BC1_UNORM_SRGB : DXGI_FORMAT_BC1_UNORM; + case eSpecial_BC2: + return format.srgbCorrected ? DXGI_FORMAT_BC2_UNORM_SRGB : DXGI_FORMAT_BC2_UNORM; + case eSpecial_BC3: + return format.srgbCorrected ? DXGI_FORMAT_BC3_UNORM_SRGB : DXGI_FORMAT_BC3_UNORM; + case eSpecial_BC4: + return format.compType == eCompType_UNorm ? DXGI_FORMAT_BC4_UNORM : DXGI_FORMAT_BC4_SNORM; + case eSpecial_BC5: + return format.compType == eCompType_UNorm ? DXGI_FORMAT_BC5_UNORM : DXGI_FORMAT_BC5_SNORM; + case eSpecial_BC6: + return format.compType == eCompType_UNorm ? DXGI_FORMAT_BC6H_UF16 : DXGI_FORMAT_BC6H_SF16; + case eSpecial_BC7: + return format.srgbCorrected ? DXGI_FORMAT_BC7_UNORM_SRGB : DXGI_FORMAT_BC7_UNORM; + case eSpecial_R10G10B10A2: + return format.compType == eCompType_UNorm ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_R10G10B10A2_UINT; + case eSpecial_R11G11B10: + return DXGI_FORMAT_R11G11B10_FLOAT; + case eSpecial_B5G6R5: + return DXGI_FORMAT_B5G6R5_UNORM; + case eSpecial_B5G5R5A1: + return DXGI_FORMAT_B5G5R5A1_UNORM; + case eSpecial_R9G9B9E5: + return DXGI_FORMAT_R9G9B9E5_SHAREDEXP; + case eSpecial_B8G8R8A8: + return format.srgbCorrected ? DXGI_FORMAT_B8G8R8A8_UNORM_SRGB : DXGI_FORMAT_B8G8R8A8_UNORM; + case eSpecial_B4G4R4A4: + return DXGI_FORMAT_B4G4R4A4_UNORM; + case eSpecial_D24S8: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case eSpecial_D32S8: + return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; + default: + case eSpecial_YUV: + RDCERR("Unsupported writing format %u", format.specialFormat); + return DXGI_FORMAT_UNKNOWN; + } + } + + if(format.compCount == 4) + { + if(format.compByteWidth == 4) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R32G32B32A32_UINT; + case eCompType_SInt: return DXGI_FORMAT_R32G32B32A32_SINT; + default: return DXGI_FORMAT_R32G32B32A32_FLOAT; + } + } + else if(format.compByteWidth == 2) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R16G16B16A16_UINT; + case eCompType_SInt: return DXGI_FORMAT_R16G16B16A16_SINT; + case eCompType_UNorm: return DXGI_FORMAT_R16G16B16A16_UNORM; + case eCompType_SNorm: return DXGI_FORMAT_R16G16B16A16_SNORM; + default: return DXGI_FORMAT_R16G16B16A16_FLOAT; + } + } + else if(format.compByteWidth == 1) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R8G8B8A8_UINT; + case eCompType_SInt: return DXGI_FORMAT_R8G8B8A8_SINT; + case eCompType_SNorm: return DXGI_FORMAT_R8G8B8A8_SNORM; + default: + case eCompType_UNorm: if(format.srgbCorrected) return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; + else return DXGI_FORMAT_R8G8B8A8_UNORM; + } + } + RDCERR("Unexpected component byte width %u for 4-component type", format.compByteWidth); + return DXGI_FORMAT_UNKNOWN; + } + else if(format.compCount == 3) + { + if(format.compByteWidth == 4) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R32G32B32_UINT; + case eCompType_SInt: return DXGI_FORMAT_R32G32B32_SINT; + default: return DXGI_FORMAT_R32G32B32_FLOAT; + } + } + RDCERR("Unexpected component byte width %u for 3-component type", format.compByteWidth); + return DXGI_FORMAT_UNKNOWN; + } + else if(format.compCount == 2) + { + if(format.compByteWidth == 4) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R32G32_UINT; + case eCompType_SInt: return DXGI_FORMAT_R32G32_SINT; + default: return DXGI_FORMAT_R32G32_FLOAT; + } + } + else if(format.compByteWidth == 2) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R16G16_UINT; + case eCompType_SInt: return DXGI_FORMAT_R16G16_SINT; + case eCompType_UNorm: return DXGI_FORMAT_R16G16_UNORM; + case eCompType_SNorm: return DXGI_FORMAT_R16G16_SNORM; + default: return DXGI_FORMAT_R16G16_FLOAT; + } + } + else if(format.compByteWidth == 1) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R8G8_UINT; + case eCompType_SInt: return DXGI_FORMAT_R8G8_SINT; + case eCompType_SNorm: return DXGI_FORMAT_R8G8_SNORM; + default: return DXGI_FORMAT_R8G8_UNORM; + } + } + RDCERR("Unexpected component byte width %u for 2-component type", format.compByteWidth); + return DXGI_FORMAT_UNKNOWN; + } + else if(format.compCount == 1) + { + if(format.compByteWidth == 4) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R32_UINT; + case eCompType_SInt: return DXGI_FORMAT_R32_SINT; + default: return DXGI_FORMAT_R32_FLOAT; + } + } + else if(format.compByteWidth == 2) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R16_UINT; + case eCompType_SInt: return DXGI_FORMAT_R16_SINT; + case eCompType_UNorm: return DXGI_FORMAT_R16_UNORM; + case eCompType_SNorm: return DXGI_FORMAT_R16_SNORM; + default: return DXGI_FORMAT_R16_FLOAT; + } + } + else if(format.compByteWidth == 1) + { + switch(format.compType) + { + case eCompType_UInt: return DXGI_FORMAT_R8_UINT; + case eCompType_SInt: return DXGI_FORMAT_R8_SINT; + case eCompType_SNorm: return DXGI_FORMAT_R8_SNORM; + default: return DXGI_FORMAT_R8_UNORM; + } + } + RDCERR("Unexpected component byte width %u for 1-component type", format.compByteWidth); + return DXGI_FORMAT_UNKNOWN; + } + + RDCERR("Unexpected component count %u", format.compCount); + return DXGI_FORMAT_UNKNOWN; +} + +bool write_dds_to_file(FILE *f, const dds_data &data) +{ + if(!f) return false; + + uint32_t magic = 0x20534444; + DDS_HEADER header; + DDS_HEADER_DXT10 headerDXT10; + RDCEraseEl(header); + RDCEraseEl(headerDXT10); + + header.dwSize = sizeof(DDS_HEADER); + + header.ddspf.dwSize = sizeof(DDS_PIXELFORMAT); + + header.dwWidth = data.width; + header.dwHeight = data.height; + header.dwDepth = data.depth; + header.dwMipMapCount = data.mips; + + header.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; + if(data.mips > 1) + header.dwFlags |= DDSD_MIPMAPCOUNT; + if(data.depth > 1) + header.dwFlags |= DDSD_DEPTH; + + bool blockFormat = false; + + if(data.format.special) + { + switch(data.format.specialFormat) + { + case eSpecial_BC1: + case eSpecial_BC2: + case eSpecial_BC3: + case eSpecial_BC4: + case eSpecial_BC5: + case eSpecial_BC6: + case eSpecial_BC7: + blockFormat = true; + default: + break; + } + } + + if(blockFormat) + header.dwFlags |= DDSD_LINEARSIZE; + else + header.dwFlags |= DDSD_PITCH; + + header.dwCaps = DDSCAPS_TEXTURE; + if(data.mips > 1) + header.dwCaps |= DDSCAPS_MIPMAP; + if(data.mips > 1 || data.slices > 1 || data.depth > 1) + header.dwCaps |= DDSCAPS_COMPLEX; + + header.dwCaps2 = data.depth > 1 ? DDSCAPS2_VOLUME : 0; + + bool dx10Header = false; + + headerDXT10.dxgiFormat = ResourceFormat2DXGIFormat(data.format); + headerDXT10.resourceDimension = data.depth > 1 ? D3D10_RESOURCE_DIMENSION_TEXTURE3D : D3D10_RESOURCE_DIMENSION_TEXTURE2D; + headerDXT10.miscFlag = 0; + headerDXT10.arraySize = data.slices; + + if(headerDXT10.dxgiFormat == DXGI_FORMAT_UNKNOWN) + return false; + + if(data.cubemap) + { + header.dwCaps2 = DDSCAPS2_CUBEMAP; + headerDXT10.miscFlag |= DDS_RESOURCE_MISC_TEXTURECUBE; + headerDXT10.arraySize /= 6; + } + + if(headerDXT10.arraySize > 1) + dx10Header = true; // need to specify dx10 header to give array size + + uint32_t bytesPerPixel = 1; + + if(blockFormat) + { + int blockSize = (data.format.specialFormat == eSpecial_BC1 || data.format.specialFormat == eSpecial_BC4) ? 8 : 16; + header.dwPitchOrLinearSize = RDCMAX(1U, ((header.dwWidth+3)/4)) * blockSize; + } + else + { + switch(data.format.specialFormat) + { + case eSpecial_R10G10B10A2: + case eSpecial_R9G9B9E5: + case eSpecial_R11G11B10: + case eSpecial_D24S8: + case eSpecial_B8G8R8A8: + bytesPerPixel = 4; + break; + case eSpecial_B5G6R5: + case eSpecial_B5G5R5A1: + case eSpecial_B4G4R4A4: + bytesPerPixel = 2; + break; + case eSpecial_D32S8: + bytesPerPixel = 5; + break; + case eSpecial_YUV: + RDCERR("Unsupported file save format"); + return false; + default: + bytesPerPixel = data.format.compCount*data.format.compByteWidth; + } + + header.dwPitchOrLinearSize = header.dwWidth * bytesPerPixel; + } + + // special case a couple of formats to write out non-DX10 style, for + // backwards compatibility + if(data.format.compByteWidth == 1 && data.format.compCount == 4) + { + header.ddspf.dwFlags = DDPF_RGBA; + header.ddspf.dwRGBBitCount = 32; + header.ddspf.dwRBitMask = 0x000000ff; + header.ddspf.dwGBitMask = 0x0000ff00; + header.ddspf.dwBBitMask = 0x00ff0000; + header.ddspf.dwABitMask = 0xff000000; + } + else if(data.format.specialFormat == eSpecial_BC1) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '1'); + } + else if(data.format.specialFormat == eSpecial_BC2) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '3'); + } + else if(data.format.specialFormat == eSpecial_BC3) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '5'); + } + else if(data.format.specialFormat == eSpecial_BC4 && data.format.compType == eCompType_UNorm) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '4', 'U'); + } + else if(data.format.specialFormat == eSpecial_BC4 && data.format.compType == eCompType_SNorm) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '4', 'S'); + } + else if(data.format.specialFormat == eSpecial_BC5 && data.format.compType == eCompType_UNorm) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('A', 'T', 'I', '2'); + } + else if(data.format.specialFormat == eSpecial_BC5 && data.format.compType == eCompType_SNorm) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '5', 'S'); + } + else + { + // just write out DX10 header + dx10Header = true; + } + + if(dx10Header) + { + header.ddspf.dwFlags = DDPF_FOURCC; + header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', '1', '0'); + } + + { + FileIO::fwrite(&magic, sizeof(magic), 1, f); + FileIO::fwrite(&header, sizeof(header), 1, f); + if(dx10Header) + FileIO::fwrite(&headerDXT10, sizeof(headerDXT10), 1, f); + + int i=0; + for(int slice=0; slice < RDCMAX(1,data.slices*data.depth); slice++) + { + for(int mip=0; mip < RDCMAX(1,data.mips); mip++) + { + byte *bytedata = data.subdata[slice * RDCMAX(1,data.mips) + mip]; + + int rowlen = RDCMAX(1, data.width>>mip); + int numRows = RDCMAX(1, data.height>>mip); + int pitch = RDCMAX(1U, rowlen * bytesPerPixel); + + // pitch/rows are in blocks, not pixels, for block formats. + if(blockFormat) + { + numRows = RDCMAX(1, numRows/4); + + int blockSize = (data.format.specialFormat == eSpecial_BC1 || data.format.specialFormat == eSpecial_BC4) ? 8 : 16; + + pitch = RDCMAX(blockSize, (((rowlen+3)/4)) * blockSize); + } + + for(int row=0; row < numRows; row++) + { + FileIO::fwrite(bytedata, 1, pitch, f); + + bytedata += pitch; + } + + i++; + } + } + } + + return true; +} diff --git a/renderdoc/common/dds_readwrite.h b/renderdoc/common/dds_readwrite.h new file mode 100644 index 000000000..30b8d1a38 --- /dev/null +++ b/renderdoc/common/dds_readwrite.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2014 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "api/replay/renderdoc_replay.h" + +struct dds_data +{ + int width; + int height; + int depth; + + int mips; + int slices; + + bool cubemap; + + ResourceFormat format; + + byte **subdata; +}; + +extern dds_data load_from_file(FILE *f); +extern bool write_dds_to_file(FILE *f, const dds_data &data); \ No newline at end of file diff --git a/renderdoc/driver/d3d11/d3d11_analyse.cpp b/renderdoc/driver/d3d11/d3d11_analyse.cpp index eddb83f80..31614f6ca 100644 --- a/renderdoc/driver/d3d11/d3d11_analyse.cpp +++ b/renderdoc/driver/d3d11/d3d11_analyse.cpp @@ -1715,309 +1715,6 @@ void D3D11DebugManager::PickPixel(ResourceId texture, uint32_t x, uint32_t y, ui m_pImmediateContext->Unmap(m_DebugRender.PickPixelStageTex, 0); } -// from MSDN -struct DDS_PIXELFORMAT { - DWORD dwSize; - DWORD dwFlags; - DWORD dwFourCC; - DWORD dwRGBBitCount; - DWORD dwRBitMask; - DWORD dwGBitMask; - DWORD dwBBitMask; - DWORD dwABitMask; -}; - -struct DDS_HEADER { - DWORD dwSize; - DWORD dwFlags; - DWORD dwHeight; - DWORD dwWidth; - DWORD dwPitchOrLinearSize; - DWORD dwDepth; - DWORD dwMipMapCount; - DWORD dwReserved1[11]; - DDS_PIXELFORMAT ddspf; - DWORD dwCaps; - DWORD dwCaps2; - DWORD dwCaps3; - DWORD dwCaps4; - DWORD dwReserved2; -}; - -struct DDS_HEADER_DXT10 { - DXGI_FORMAT dxgiFormat; - D3D10_RESOURCE_DIMENSION resourceDimension; - UINT miscFlag; - UINT arraySize; - UINT reserved; -}; - -#define DDSD_CAPS 0x1 -#define DDSD_HEIGHT 0x2 -#define DDSD_WIDTH 0x4 -#define DDSD_PITCH 0x8 -#define DDSD_PIXELFORMAT 0x1000 -#define DDSD_MIPMAPCOUNT 0x20000 -#define DDSD_LINEARSIZE 0x80000 -#define DDSD_DEPTH 0x800000 - -#define DDSCAPS_COMPLEX 0x8 -#define DDSCAPS_MIPMAP 0x400000 -#define DDSCAPS_TEXTURE 0x1000 - -#define DDSCAPS2_CUBEMAP 0xff00 // d3d10+ requires all cubemap faces -#define DDSCAPS2_VOLUME 0x200000 - -#define DDPF_ALPHAPIXELS 0x1 -#define DDPF_ALPHA 0x2 -#define DDPF_FOURCC 0x4 -#define DDPF_RGB 0x40 -#define DDPF_YUV 0x200 -#define DDPF_LUMINANCE 0x20000 -#define DDPF_RGBA (DDPF_RGB|DDPF_ALPHAPIXELS) - -bool D3D11DebugManager::SaveTexture(ResourceId id, uint32_t saveMip, wstring path) -{ - if(WrappedID3D11Texture2D::m_TextureList.find(id) == WrappedID3D11Texture2D::m_TextureList.end()) - return false; - - WrappedID3D11Texture2D *wrapTex = (WrappedID3D11Texture2D *)WrappedID3D11Texture2D::m_TextureList[id].m_Texture; - - if(path.find(L".dds") != wstring::npos) - { - D3D11_TEXTURE2D_DESC desc = {0}; - wrapTex->GetDesc(&desc); - - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.MiscFlags = 0; - desc.Usage = D3D11_USAGE_STAGING; - - ID3D11Texture2D *dummyTex = NULL; - - HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &dummyTex); - - if(FAILED(hr)) - { - RDCERR("Couldn't create staging texture to save. %08x", hr); - return false; - } - - m_pImmediateContext->CopyResource(dummyTex, wrapTex->GetReal()); - - DWORD magic = 0x20534444; - DDS_HEADER header; - DDS_HEADER_DXT10 headerDXT10; - RDCEraseEl(header); - RDCEraseEl(headerDXT10); - - header.dwSize = sizeof(DDS_HEADER); - - header.ddspf.dwSize = sizeof(DDS_PIXELFORMAT); - - header.dwWidth = desc.Width; - header.dwHeight = desc.Height; - header.dwDepth = 0; - header.dwMipMapCount = desc.MipLevels; - - header.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT; - if(desc.MipLevels > 1) - header.dwFlags |= DDSD_MIPMAPCOUNT; - if(IsDepthFormat(desc.Format)) - header.dwFlags |= DDSD_DEPTH; - if(IsBlockFormat(desc.Format)) - header.dwFlags |= DDSD_LINEARSIZE; - else - header.dwFlags |= DDSD_PITCH; - - header.dwCaps = DDSCAPS_TEXTURE; - /* - // spec compliant, but seems to confuse DirectX Texture Tool :( - if(desc.MipLevels > 1) - header.dwCaps |= DDSCAPS_MIPMAP; - if(desc.MipLevels > 1 || desc.ArraySize > 1) - header.dwCaps |= DDSCAPS_COMPLEX; - */ - if(desc.ArraySize > 1) - header.dwCaps |= DDSCAPS_COMPLEX; - - header.dwCaps2 = desc.ArraySize > 1 ? DDSCAPS2_VOLUME : 0; - - bool dx10Header = false; - - headerDXT10.dxgiFormat = GetTypedFormat(desc.Format); - headerDXT10.resourceDimension = D3D10_RESOURCE_DIMENSION_TEXTURE2D; - headerDXT10.arraySize = desc.ArraySize; - - if(desc.MiscFlags & D3D11_RESOURCE_MISC_TEXTURECUBE) - { - header.dwCaps2 = DDSCAPS2_CUBEMAP; - } - - if(headerDXT10.arraySize > 1) - dx10Header = true; // need to specify dx10 header to give array size - - if(IsBlockFormat(desc.Format)) - { - int blockSize = GetFormatBPP(desc.Format) / 8; - header.dwPitchOrLinearSize = RDCMAX(1U, ((desc.Width+3)/4)) * blockSize; - } - else if(desc.Format == DXGI_FORMAT_R8G8_B8G8_UNORM || - desc.Format == DXGI_FORMAT_G8R8_G8B8_UNORM) - { - header.dwPitchOrLinearSize = ((desc.Width+1) >> 1) * 4; - } - else - { - header.dwPitchOrLinearSize = (desc.Width * GetFormatBPP(desc.Format) + 7) / 8; - } - - // special case a couple of formats to write out non-DX10 style, for - // backwards compatibility - switch(desc.Format) - { - case DXGI_FORMAT_R8G8B8A8_TYPELESS: - case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - case DXGI_FORMAT_R8G8B8A8_UINT: - case DXGI_FORMAT_R8G8B8A8_SNORM: - case DXGI_FORMAT_R8G8B8A8_SINT: - { - header.ddspf.dwFlags = DDPF_RGBA; - header.ddspf.dwRGBBitCount = 32; - header.ddspf.dwRBitMask = 0x000000ff; - header.ddspf.dwGBitMask = 0x0000ff00; - header.ddspf.dwBBitMask = 0x00ff0000; - header.ddspf.dwABitMask = 0xff000000; - break; - } - case DXGI_FORMAT_BC1_TYPELESS: - case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '1'); - break; - } - case DXGI_FORMAT_BC2_TYPELESS: - case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '3'); - break; - } - case DXGI_FORMAT_BC3_TYPELESS: - case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', 'T', '5'); - break; - } - case DXGI_FORMAT_BC4_TYPELESS: - case DXGI_FORMAT_BC4_UNORM: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '4', 'U'); - break; - } - case DXGI_FORMAT_BC4_SNORM: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '4', 'S'); - break; - } - case DXGI_FORMAT_BC5_TYPELESS: - case DXGI_FORMAT_BC5_UNORM: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('A', 'T', 'I', '2'); - break; - } - case DXGI_FORMAT_BC5_SNORM: - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('B', 'C', '5', 'S'); - break; - } - default: - { - // just write out DX10 header - dx10Header = true; - break; - } - } - - if(dx10Header) - { - header.ddspf.dwFlags = DDPF_FOURCC; - header.ddspf.dwFourCC = MAKE_FOURCC('D', 'X', '1', '0'); - } - - FILE *f = FileIO::fopen(path.c_str(), L"wb"); - - if(f) - { - FileIO::fwrite(&magic, sizeof(magic), 1, f); - FileIO::fwrite(&header, sizeof(header), 1, f); - if(dx10Header) - FileIO::fwrite(&headerDXT10, sizeof(headerDXT10), 1, f); - - UINT i=0; - for(UINT slice=0; slice < RDCMAX(1U,desc.ArraySize); slice++) - { - for(UINT mip=0; mip < RDCMAX(1U,desc.MipLevels); mip++) - { - D3D11_MAPPED_SUBRESOURCE mapped; - hr = m_pImmediateContext->Map(dummyTex, i, D3D11_MAP_READ, 0, &mapped); - - if(FAILED(hr)) - { - RDCERR("Couldn't map subresource. %08x", hr); - FileIO::fclose(f); - return false; - } - - byte *data = (byte *)mapped.pData; - - UINT numRows = (desc.Height>>mip); - UINT pitch = (header.dwPitchOrLinearSize>>mip); - - // pitch/rows are in blocks, not pixels, for block formats. - if(IsBlockFormat(desc.Format)) - { - numRows = RDCMAX(1U, numRows/4); - // at least one block - pitch = RDCMAX(pitch, GetFormatBPP(desc.Format)/8); - } - - for(UINT row=0; row < numRows; row++) - { - FileIO::fwrite(data, 1, pitch, f); - - data += mapped.RowPitch; - } - - m_pImmediateContext->Unmap(dummyTex, i); - - i++; - } - } - } - - FileIO::fclose(f); - - SAFE_RELEASE(dummyTex); - - return true; - } - - RDCERR("Unknown file-type"); - - return false; -} - byte *D3D11DebugManager::GetTextureData(ResourceId id, uint32_t arrayIdx, uint32_t mip, size_t &dataSize) { ID3D11Resource *dummyTex = NULL; diff --git a/renderdoc/driver/d3d11/d3d11_debug.h b/renderdoc/driver/d3d11/d3d11_debug.h index 9007d232b..0cf16b758 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.h +++ b/renderdoc/driver/d3d11/d3d11_debug.h @@ -127,8 +127,6 @@ class D3D11DebugManager void TimeDrawcalls(rdctype::array &arr); - bool SaveTexture(ResourceId tex, uint32_t saveMip, wstring path); - void RenderText(float x, float y, float size, const char *textfmt, ...); void RenderMesh(uint32_t frameID, const vector &events, MeshDisplay cfg); diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 907733e20..cbd2cdc79 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -240,6 +240,7 @@ + @@ -306,6 +307,7 @@ + NoListing diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index 171424035..eea95cd14 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -85,6 +85,9 @@ {188b97fd-b9d4-47a6-a51a-48bc00e6fc5c} + + {eb0686f4-bcb3-4edd-b488-937b1491909b} + @@ -312,6 +315,9 @@ API\Replay + + Common\File Formats + @@ -536,6 +542,9 @@ 3rdparty\stb + + Common\File Formats + diff --git a/renderdoc/replay/replay_renderer.cpp b/renderdoc/replay/replay_renderer.cpp index 94819cbb6..f3e0a2995 100644 --- a/renderdoc/replay/replay_renderer.cpp +++ b/renderdoc/replay/replay_renderer.cpp @@ -33,6 +33,12 @@ #include "serialise/serialiser.h" +#include "3rdparty/jpeg-compressor/jpgd.h" +#include "3rdparty/jpeg-compressor/jpge.h" +#include "3rdparty/stb/stb_image.h" +#include "3rdparty/stb/stb_image_write.h" +#include "common/dds_readwrite.h" + ReplayRenderer::ReplayRenderer() { m_pDevice = NULL;