Skip to content

Commit f32d0c2

Browse files
authored
Merge pull request #17083 from hrydgard/dds-support
DDS texture support in texture replacer
2 parents a651fd8 + 996b685 commit f32d0c2

22 files changed

+417
-90
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,8 @@ add_library(Common STATIC
571571
Common/Data/Format/JSONReader.cpp
572572
Common/Data/Format/JSONWriter.h
573573
Common/Data/Format/JSONWriter.cpp
574+
Common/Data/Format/DDSLoad.cpp
575+
Common/Data/Format/DDSLoad.h
574576
Common/Data/Format/PNGLoad.cpp
575577
Common/Data/Format/PNGLoad.h
576578
Common/Data/Format/ZIMLoad.cpp

Common/Common.vcxproj

+2
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@
405405
<ClInclude Include="Data\Encoding\Shiftjis.h" />
406406
<ClInclude Include="Data\Encoding\Utf16.h" />
407407
<ClInclude Include="Data\Encoding\Utf8.h" />
408+
<ClInclude Include="Data\Format\DDSLoad.h" />
408409
<ClInclude Include="Data\Format\IniFile.h" />
409410
<ClInclude Include="Data\Format\JSONReader.h" />
410411
<ClInclude Include="Data\Format\JSONWriter.h" />
@@ -844,6 +845,7 @@
844845
<ClCompile Include="Data\Encoding\Base64.cpp" />
845846
<ClCompile Include="Data\Encoding\Compression.cpp" />
846847
<ClCompile Include="Data\Encoding\Utf8.cpp" />
848+
<ClCompile Include="Data\Format\DDSLoad.cpp" />
847849
<ClCompile Include="Data\Format\IniFile.cpp" />
848850
<ClCompile Include="Data\Format\JSONReader.cpp" />
849851
<ClCompile Include="Data\Format\JSONWriter.cpp" />

Common/Common.vcxproj.filters

+6
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,9 @@
470470
<ClInclude Include="File\VFS\ZipFileReader.h">
471471
<Filter>File\VFS</Filter>
472472
</ClInclude>
473+
<ClInclude Include="Data\Format\DDSLoad.h">
474+
<Filter>Data\Format</Filter>
475+
</ClInclude>
473476
</ItemGroup>
474477
<ItemGroup>
475478
<ClCompile Include="ABI.cpp" />
@@ -890,6 +893,9 @@
890893
<ClCompile Include="File\VFS\ZipFileReader.cpp">
891894
<Filter>File\VFS</Filter>
892895
</ClCompile>
896+
<ClCompile Include="Data\Format\DDSLoad.cpp">
897+
<Filter>Data\Format</Filter>
898+
</ClCompile>
893899
</ItemGroup>
894900
<ItemGroup>
895901
<Filter Include="Crypto">

Common/Data/Format/DDSLoad.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include "Common/Data/Format/DDSLoad.h"
2+
3+
bool DetectDDSParams(const DDSHeader *header, DDSLoadInfo *info) {
4+
return false;
5+
}

Common/Data/Format/DDSLoad.h

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
// DDSPixelFormat.dwFlags bits
6+
enum {
7+
DDPF_ALPHAPIXELS = 1, // Texture contains alpha data; dwRGBAlphaBitMask contains valid data.
8+
DDPF_ALPHA = 2, // Used in some older DDS files for alpha channel only uncompressed data(dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data)
9+
DDPF_FOURCC = 4, // Texture contains compressed RGB data; dwFourCC contains valid data. 0x4
10+
DDPF_RGB = 8, // Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks(dwRBitMask, dwGBitMask, dwBBitMask) contain valid data. 0x40
11+
DDPF_YUV = 16, //Used in some older DDS files for YUV uncompressed data(dwRGBBitCount contains the YUV bit count; dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask)
12+
DDPF_LUMINANCE = 32, // Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count; dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file.
13+
};
14+
15+
// dwCaps members
16+
enum {
17+
DDSCAPS_COMPLEX = 8,
18+
DDSCAPS_MIPMAP = 0x400000,
19+
DDSCAPS_TEXTURE = 0x1000, // Required
20+
};
21+
22+
// Not using any D3D headers here, this is cross platform and minimal.
23+
// Boiled down from the public documentation.
24+
struct DDSPixelFormat {
25+
uint32_t dwSize; // must be 32
26+
uint32_t dwFlags;
27+
uint32_t dwFourCC;
28+
uint32_t dwRGBBitCount;
29+
uint32_t dwRBitMask;
30+
uint32_t dwGBitMask;
31+
uint32_t dwBBitMask;
32+
uint32_t dwABitMask;
33+
};
34+
35+
struct DDSHeader {
36+
uint32_t dwMagic; // Magic is not technically part of the header struct but convenient to have here when reading the files.
37+
uint32_t dwSize; // must be 124
38+
uint32_t dwFlags;
39+
uint32_t dwHeight;
40+
uint32_t dwWidth;
41+
uint32_t dwPitchOrLinearSize; // The pitch or number of bytes per scan line in an uncompressed texture; the total number of bytes in the top level texture for a compressed texture
42+
uint32_t dwDepth; // we'll always use 1 here
43+
uint32_t dwMipMapCount;
44+
uint32_t dwReserved1[11];
45+
DDSPixelFormat ddspf;
46+
uint32_t dwCaps;
47+
uint32_t dwCaps2; // nothing we care about
48+
uint32_t dwCaps3; // unused
49+
uint32_t dwCaps4; // unused
50+
uint32_t dwReserved2;
51+
};
52+
53+
// DDS header extension to handle resource arrays, DXGI pixel formats that don't map to the legacy Microsoft DirectDraw pixel format structures, and additional metadata.
54+
struct DDSHeaderDXT10 {
55+
uint32_t dxgiFormat;
56+
uint32_t resourceDimension; // 1d = 2, 2d = 3, 3d = 4. very intuitive
57+
uint32_t miscFlag;
58+
uint32_t arraySize; // we only support 1 here
59+
uint32_t miscFlags2; // sets alpha interpretation, let's not bother
60+
};
61+
62+
// Simple DDS parser, suitable for texture replacement packs.
63+
// Doesn't actually load, only does some logic to fill out DDSLoadInfo so the caller can then
64+
// do the actual load with a simple series of memcpys or whatever is appropriate.
65+
struct DDSLoadInfo {
66+
uint32_t bytesToCopy;
67+
};
68+
69+
bool DetectDDSParams(const DDSHeader *header, DDSLoadInfo *info);

Common/GPU/D3D11/thin3d_d3d11.cpp

+6-1
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,12 @@ static DXGI_FORMAT dataFormatToD3D11(DataFormat format) {
491491
case DataFormat::D16: return DXGI_FORMAT_D16_UNORM;
492492
case DataFormat::D32F: return DXGI_FORMAT_D32_FLOAT;
493493
case DataFormat::D32F_S8: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
494-
case DataFormat::ETC1:
494+
case DataFormat::BC1_RGBA_UNORM_BLOCK: return DXGI_FORMAT_BC1_UNORM;
495+
case DataFormat::BC2_UNORM_BLOCK: return DXGI_FORMAT_BC2_UNORM;
496+
case DataFormat::BC3_UNORM_BLOCK: return DXGI_FORMAT_BC3_UNORM;
497+
case DataFormat::BC4_UNORM_BLOCK: return DXGI_FORMAT_BC4_UNORM;
498+
case DataFormat::BC5_UNORM_BLOCK: return DXGI_FORMAT_BC5_UNORM;
499+
case DataFormat::BC7_UNORM_BLOCK: return DXGI_FORMAT_BC7_UNORM;
495500
default:
496501
return DXGI_FORMAT_UNKNOWN;
497502
}

Common/GPU/D3D9/thin3d_d3d9.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,9 @@ D3DFORMAT FormatToD3DFMT(DataFormat fmt) {
125125
case DataFormat::A1R5G5B5_UNORM_PACK16: return D3DFMT_A1R5G5B5;
126126
case DataFormat::D24_S8: return D3DFMT_D24S8;
127127
case DataFormat::D16: return D3DFMT_D16;
128+
case DataFormat::BC1_RGBA_UNORM_BLOCK: return D3DFMT_DXT1;
129+
case DataFormat::BC2_UNORM_BLOCK: return D3DFMT_DXT3; // DXT3 is indeed BC2.
130+
case DataFormat::BC3_UNORM_BLOCK: return D3DFMT_DXT5; // DXT5 is indeed BC3
128131
default: return D3DFMT_UNKNOWN;
129132
}
130133
}

Common/GPU/DataFormat.h

+15-16
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,20 @@ enum class DataFormat : uint8_t {
4646
// Block compression formats.
4747
// These are modern names for DXT and friends, now patent free.
4848
// https://msdn.microsoft.com/en-us/library/bb694531.aspx
49-
BC1_RGBA_UNORM_BLOCK,
50-
BC1_RGBA_SRGB_BLOCK,
51-
BC2_UNORM_BLOCK, // 4-bit straight alpha + DXT1 color. Usually not worth using
52-
BC2_SRGB_BLOCK,
53-
BC3_UNORM_BLOCK, // 3-bit alpha with 2 ref values (+ magic) + DXT1 color
54-
BC3_SRGB_BLOCK,
55-
BC4_UNORM_BLOCK, // 1-channel, same storage as BC3 alpha
56-
BC4_SNORM_BLOCK,
57-
BC5_UNORM_BLOCK, // 2-channel RG, each has same storage as BC3 alpha
58-
BC5_SNORM_BLOCK,
59-
BC6H_UFLOAT_BLOCK, // TODO
60-
BC6H_SFLOAT_BLOCK,
61-
BC7_UNORM_BLOCK, // Highly advanced, very expensive to compress, very good quality.
62-
BC7_SRGB_BLOCK,
63-
64-
ETC1,
49+
BC1_RGBA_UNORM_BLOCK, // 64 bits per 4x4 block. Used by Basis, along with ETC2_R8G8B8_UNORM_BLOCK.
50+
BC2_UNORM_BLOCK, // 4-bit straight alpha + DXT1 color. 128 bits per block. Usually not worth using
51+
BC3_UNORM_BLOCK, // 3-bit alpha with 2 ref values (+ magic) + DXT1 color. 128 bits per block.
52+
BC4_UNORM_BLOCK, // 1-channel, same storage as BC3 alpha. 64 bits per block.
53+
BC5_UNORM_BLOCK, // 2-channel RG, each has same storage as BC3 alpha. 128 bits per block.
54+
BC7_UNORM_BLOCK, // Highly advanced RGBA, very expensive to compress, very good quality. 128 bits per block.
55+
56+
// Ericsson texture compression.
57+
ETC2_R8G8B8_UNORM_BLOCK, // Color-only, 64 bits per 4x4 block.
58+
ETC2_R8G8B8A1_UNORM_BLOCK, // Color + alpha, 128 bits per 4x4 block.
59+
ETC2_R8G8B8A8_UNORM_BLOCK, // Color + alpha, 128 bits per 4x4 block.
60+
61+
// This is the one ASTC format used by UASTC / basis Universal.
62+
ASTC_4x4_UNORM_BLOCK,
6563

6664
S8,
6765
D16,
@@ -76,6 +74,7 @@ bool DataFormatIsDepthStencil(DataFormat fmt);
7674
inline bool DataFormatIsColor(DataFormat fmt) {
7775
return !DataFormatIsDepthStencil(fmt);
7876
}
77+
bool DataFormatIsBlockCompressed(DataFormat fmt, int *blockSize);
7978

8079
// Limited format support for now.
8180
const char *DataFormatToString(DataFormat fmt);

Common/GPU/OpenGL/DataFormatGL.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,50 @@ bool Thin3DFormatToGLFormatAndType(DataFormat fmt, GLuint &internalFormat, GLuin
8686
alignment = 16;
8787
break;
8888

89+
#if PPSSPP_PLATFORM(WINDOWS)
90+
case DataFormat::BC1_RGBA_UNORM_BLOCK:
91+
internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
92+
format = GL_RGB;
93+
type = GL_FLOAT;
94+
alignment = 8;
95+
break;
96+
97+
case DataFormat::BC7_UNORM_BLOCK:
98+
internalFormat = GL_COMPRESSED_RGBA_BPTC_UNORM;
99+
format = GL_RGBA;
100+
type = GL_FLOAT;
101+
alignment = 16;
102+
break;
103+
#endif
104+
105+
case DataFormat::ETC2_R8G8B8_UNORM_BLOCK:
106+
internalFormat = GL_COMPRESSED_RGB8_ETC2;
107+
format = GL_RGB;
108+
type = GL_FLOAT;
109+
alignment = 8;
110+
break;
111+
112+
case DataFormat::ETC2_R8G8B8A1_UNORM_BLOCK:
113+
internalFormat = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
114+
format = GL_RGBA;
115+
type = GL_FLOAT;
116+
alignment = 16;
117+
break;
118+
119+
case DataFormat::ETC2_R8G8B8A8_UNORM_BLOCK:
120+
internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC;
121+
format = GL_RGBA;
122+
type = GL_FLOAT;
123+
alignment = 16;
124+
break;
125+
126+
case DataFormat::ASTC_4x4_UNORM_BLOCK:
127+
internalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
128+
format = GL_RGBA;
129+
type = GL_FLOAT;
130+
alignment = 16;
131+
break;
132+
89133
default:
90134
return false;
91135
}

Common/GPU/Vulkan/thin3d_vulkan.cpp

+23-5
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,7 @@ class VKContext : public DrawContext {
560560
uint8_t stencilCompareMask_ = 0xFF;
561561
};
562562

563+
// Bits per pixel, not bytes.
563564
static int GetBpp(VkFormat format) {
564565
switch (format) {
565566
case VK_FORMAT_R8G8B8A8_UNORM:
@@ -582,6 +583,21 @@ static int GetBpp(VkFormat format) {
582583
return 32;
583584
case VK_FORMAT_D16_UNORM:
584585
return 16;
586+
case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK:
587+
return 4;
588+
case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK:
589+
case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK:
590+
return 8;
591+
case VK_FORMAT_ASTC_4x4_UNORM_BLOCK:
592+
return 8;
593+
case VK_FORMAT_BC1_RGBA_UNORM_BLOCK:
594+
return 4;
595+
case VK_FORMAT_BC2_UNORM_BLOCK:
596+
case VK_FORMAT_BC3_UNORM_BLOCK:
597+
case VK_FORMAT_BC4_UNORM_BLOCK:
598+
case VK_FORMAT_BC5_UNORM_BLOCK:
599+
case VK_FORMAT_BC7_UNORM_BLOCK:
600+
return 8;
585601
default:
586602
return 0;
587603
}
@@ -625,13 +641,15 @@ static VkFormat DataFormatToVulkan(DataFormat format) {
625641
case DataFormat::BC2_UNORM_BLOCK: return VK_FORMAT_BC2_UNORM_BLOCK;
626642
case DataFormat::BC3_UNORM_BLOCK: return VK_FORMAT_BC3_UNORM_BLOCK;
627643
case DataFormat::BC4_UNORM_BLOCK: return VK_FORMAT_BC4_UNORM_BLOCK;
628-
case DataFormat::BC4_SNORM_BLOCK: return VK_FORMAT_BC4_SNORM_BLOCK;
629644
case DataFormat::BC5_UNORM_BLOCK: return VK_FORMAT_BC5_UNORM_BLOCK;
630-
case DataFormat::BC5_SNORM_BLOCK: return VK_FORMAT_BC5_SNORM_BLOCK;
631-
case DataFormat::BC6H_SFLOAT_BLOCK: return VK_FORMAT_BC6H_SFLOAT_BLOCK;
632-
case DataFormat::BC6H_UFLOAT_BLOCK: return VK_FORMAT_BC6H_UFLOAT_BLOCK;
633645
case DataFormat::BC7_UNORM_BLOCK: return VK_FORMAT_BC7_UNORM_BLOCK;
634-
case DataFormat::BC7_SRGB_BLOCK: return VK_FORMAT_BC7_SRGB_BLOCK;
646+
647+
case DataFormat::ETC2_R8G8B8A1_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK;
648+
case DataFormat::ETC2_R8G8B8A8_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK;
649+
case DataFormat::ETC2_R8G8B8_UNORM_BLOCK: return VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK;
650+
651+
case DataFormat::ASTC_4x4_UNORM_BLOCK: return VK_FORMAT_ASTC_4x4_UNORM_BLOCK;
652+
635653
default:
636654
return VK_FORMAT_UNDEFINED;
637655
}

Common/GPU/thin3d.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,31 @@ bool DataFormatIsDepthStencil(DataFormat fmt) {
9393
}
9494
}
9595

96+
// We don't bother listing the formats that are irrelevant for PPSSPP, like BC6 (HDR format)
97+
// or weird-shaped ASTC formats. We only support 4x4 block size formats for now.
98+
// If you pass in a blockSize parameter, it receives byte count that a 4x4 block takes in this format.
99+
bool DataFormatIsBlockCompressed(DataFormat fmt, int *blockSize) {
100+
switch (fmt) {
101+
case DataFormat::BC1_RGBA_UNORM_BLOCK:
102+
case DataFormat::BC4_UNORM_BLOCK:
103+
case DataFormat::ETC2_R8G8B8_UNORM_BLOCK:
104+
if (blockSize) *blockSize = 8; // 64 bits
105+
return true;
106+
case DataFormat::BC2_UNORM_BLOCK:
107+
case DataFormat::BC3_UNORM_BLOCK:
108+
case DataFormat::BC5_UNORM_BLOCK:
109+
case DataFormat::BC7_UNORM_BLOCK:
110+
case DataFormat::ETC2_R8G8B8A1_UNORM_BLOCK:
111+
case DataFormat::ETC2_R8G8B8A8_UNORM_BLOCK:
112+
case DataFormat::ASTC_4x4_UNORM_BLOCK:
113+
if (blockSize) *blockSize = 16; // 128 bits
114+
return true;
115+
default:
116+
if (blockSize) *blockSize = 0;
117+
return false;
118+
}
119+
}
120+
96121
RefCountedObject::~RefCountedObject() {
97122
_dbg_assert_(refcount_ == 0xDEDEDE);
98123
}

0 commit comments

Comments
 (0)