2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "DirectXGraphics.h"
14 LPVOID
XPhysicalAlloc(SIZE_T s
, DWORD ulPhysicalAddress
, DWORD ulAlignment
, DWORD flProtect
)
19 void XPhysicalFree(LPVOID lpAddress
)
24 DWORD
GetD3DFormat(XB_D3DFORMAT format
)
27 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
28 ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \
29 ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
33 case XB_D3DFMT_A8R8G8B8
:
34 case XB_D3DFMT_LIN_A8R8G8B8
:
38 return MAKEFOURCC('D', 'X', 'T', '1');
40 return MAKEFOURCC('D', 'X', 'T', '2');
42 return MAKEFOURCC('D', 'X', 'T', '4');
48 DWORD
BytesPerPixelFromFormat(XB_D3DFORMAT format
)
52 case XB_D3DFMT_A8R8G8B8
:
53 case XB_D3DFMT_LIN_A8R8G8B8
:
65 bool IsPalettedFormat(XB_D3DFORMAT format
)
67 if (format
== XB_D3DFMT_P8
)
72 void ParseTextureHeader(D3DTexture
*tex
, XB_D3DFORMAT
&fmt
, DWORD
&width
, DWORD
&height
, DWORD
&pitch
, DWORD
&offset
)
74 fmt
= (XB_D3DFORMAT
)((tex
->Format
& 0xff00) >> 8);
78 width
= (tex
->Size
& 0x00000fff) + 1;
79 height
= ((tex
->Size
& 0x00fff000) >> 12) + 1;
80 pitch
= (((tex
->Size
& 0xff000000) >> 24) + 1) << 6;
84 width
= 1 << ((tex
->Format
& 0x00f00000) >> 20);
85 height
= 1 << ((tex
->Format
& 0x0f000000) >> 24);
86 pitch
= width
* BytesPerPixelFromFormat(fmt
);
90 bool IsSwizzledFormat(XB_D3DFORMAT format
)
94 case XB_D3DFMT_A8R8G8B8
:
110 // Currently only works for 32bit and 8bit textures, with power of 2 width and height
111 void Unswizzle(const void *src
, unsigned int depth
, unsigned int width
, unsigned int height
, void *dest
)
113 if (height
== 0 || width
== 0)
116 for (UINT y
= 0; y
< height
; y
++)
121 for (int bit
= 0; bit
< 16; bit
++)
122 sy
|= ((y
>> bit
) & 1) << (2*bit
);
123 sy
<<= 1; // y counts twice
127 UINT y_mask
= y
% width
;
128 for (int bit
= 0; bit
< 16; bit
++)
129 sy
|= ((y_mask
>> bit
) & 1) << (2*bit
);
130 sy
<<= 1; // y counts twice
131 sy
+= (y
/ width
) * width
* width
;
133 BYTE
*d
= (BYTE
*)dest
+ y
* width
* depth
;
134 for (UINT x
= 0; x
< width
; x
++)
139 for (int bit
= 0; bit
< 16; bit
++)
140 sx
|= ((x
>> bit
) & 1) << (2*bit
);
144 int x_mask
= x
% (2*height
);
145 for (int bit
= 0; bit
< 16; bit
++)
146 sx
|= ((x_mask
>> bit
) & 1) << (2*bit
);
147 sx
+= (x
/ (2 * height
)) * 2 * height
* height
;
149 BYTE
*s
= (BYTE
*)src
+ (sx
+ sy
)*depth
;
150 for (unsigned int i
= 0; i
< depth
; ++i
)
156 void DXT1toARGB(const void *src
, void *dest
, unsigned int destWidth
)
158 const BYTE
*b
= (const BYTE
*)src
;
159 // colour is in R5G6B5 format, convert to R8G8B8
164 for (int i
= 0; i
< 2; i
++)
166 red
[i
] = b
[2*i
+1] & 0xf8;
167 green
[i
] = ((b
[2*i
+1] & 0x7) << 5) | ((b
[2*i
] & 0xe0) >> 3);
168 blue
[i
] = (b
[2*i
] & 0x1f) << 3;
169 colour
[i
] = (red
[i
] << 16) | (green
[i
] << 8) | blue
[i
];
171 if (colour
[0] > colour
[1])
173 red
[2] = (2 * red
[0] + red
[1] + 1) / 3;
174 green
[2] = (2 * green
[0] + green
[1] + 1) / 3;
175 blue
[2] = (2 * blue
[0] + blue
[1] + 1) / 3;
176 red
[3] = (red
[0] + 2 * red
[1] + 1) / 3;
177 green
[3] = (green
[0] + 2 * green
[1] + 1) / 3;
178 blue
[3] = (blue
[0] + 2 * blue
[1] + 1) / 3;
179 for (int i
= 0; i
< 4; i
++)
180 colour
[i
] = (red
[i
] << 16) | (green
[i
] << 8) | blue
[i
] | 0xFF000000;
184 red
[2] = (red
[0] + red
[1]) / 2;
185 green
[2] = (green
[0] + green
[1]) / 2;
186 blue
[2] = (blue
[0] + blue
[1]) / 2;
187 for (int i
= 0; i
< 3; i
++)
188 colour
[i
] = (red
[i
] << 16) | (green
[i
] << 8) | blue
[i
] | 0xFF000000;
189 colour
[3] = 0; // transparent
191 // ok, now grab the bits
192 for (int y
= 0; y
< 4; y
++)
194 DWORD
*d
= (DWORD
*)dest
+ destWidth
* y
;
195 *d
++ = colour
[(b
[4 + y
] & 0x03)];
196 *d
++ = colour
[(b
[4 + y
] & 0x0c) >> 2];
197 *d
++ = colour
[(b
[4 + y
] & 0x30) >> 4];
198 *d
++ = colour
[(b
[4 + y
] & 0xc0) >> 6];
202 void DXT4toARGB(const void *src
, void *dest
, unsigned int destWidth
)
204 const BYTE
*b
= (const BYTE
*)src
;
208 if (alpha
[0] > alpha
[1])
210 alpha
[2] = (6 * alpha
[0] + 1 * alpha
[1]+ 3) / 7;
211 alpha
[3] = (5 * alpha
[0] + 2 * alpha
[1] + 3) / 7; // bit code 011
212 alpha
[4] = (4 * alpha
[0] + 3 * alpha
[1] + 3) / 7; // bit code 100
213 alpha
[5] = (3 * alpha
[0] + 4 * alpha
[1] + 3) / 7; // bit code 101
214 alpha
[6] = (2 * alpha
[0] + 5 * alpha
[1] + 3) / 7; // bit code 110
215 alpha
[7] = (1 * alpha
[0] + 6 * alpha
[1] + 3) / 7; // bit code 111
219 alpha
[2] = (4 * alpha
[0] + 1 * alpha
[1] + 2) / 5; // Bit code 010
220 alpha
[3] = (3 * alpha
[0] + 2 * alpha
[1] + 2) / 5; // Bit code 011
221 alpha
[4] = (2 * alpha
[0] + 3 * alpha
[1] + 2) / 5; // Bit code 100
222 alpha
[5] = (1 * alpha
[0] + 4 * alpha
[1] + 2) / 5; // Bit code 101
223 alpha
[6] = 0; // Bit code 110
224 alpha
[7] = 255; // Bit code 111
226 // ok, now grab the bits
228 a
[0][0] = alpha
[(b
[2] & 0xe0) >> 5];
229 a
[0][1] = alpha
[(b
[2] & 0x1c) >> 2];
230 a
[0][2] = alpha
[((b
[2] & 0x03) << 1) | ((b
[3] & 0x80) >> 7)];
231 a
[0][3] = alpha
[(b
[3] & 0x70) >> 4];
232 a
[1][0] = alpha
[(b
[3] & 0x0e) >> 1];
233 a
[1][1] = alpha
[((b
[3] & 0x01) << 2) | ((b
[4] & 0xc0) >> 6)];
234 a
[1][2] = alpha
[(b
[4] & 0x38) >> 3];
235 a
[1][3] = alpha
[(b
[4] & 0x07)];
236 a
[2][0] = alpha
[(b
[5] & 0xe0) >> 5];
237 a
[2][1] = alpha
[(b
[5] & 0x1c) >> 2];
238 a
[2][2] = alpha
[((b
[5] & 0x03) << 1) | ((b
[6] & 0x80) >> 7)];
239 a
[2][3] = alpha
[(b
[6] & 0x70) >> 4];
240 a
[3][0] = alpha
[(b
[6] & 0x0e) >> 1];
241 a
[3][1] = alpha
[((b
[6] & 0x01) << 2) | ((b
[7] & 0xc0) >> 6)];
242 a
[3][2] = alpha
[(b
[7] & 0x38) >> 3];
243 a
[3][3] = alpha
[(b
[7] & 0x07)];
246 // colour is in R5G6B5 format, convert to R8G8B8
251 for (int i
= 0; i
< 2; i
++)
253 red
[i
] = b
[2*i
+1] & 0xf8;
254 green
[i
] = ((b
[2*i
+1] & 0x7) << 5) | ((b
[2*i
] & 0xe0) >> 3);
255 blue
[i
] = (b
[2*i
] & 0x1f) << 3;
257 red
[2] = (2 * red
[0] + red
[1] + 1) / 3;
258 green
[2] = (2 * green
[0] + green
[1] + 1) / 3;
259 blue
[2] = (2 * blue
[0] + blue
[1] + 1) / 3;
260 red
[3] = (red
[0] + 2 * red
[1] + 1) / 3;
261 green
[3] = (green
[0] + 2 * green
[1] + 1) / 3;
262 blue
[3] = (blue
[0] + 2 * blue
[1] + 1) / 3;
263 for (int i
= 0; i
< 4; i
++)
264 colour
[i
] = (red
[i
] << 16) | (green
[i
] << 8) | blue
[i
];
265 // and assign them to our texture
266 for (int y
= 0; y
< 4; y
++)
268 DWORD
*d
= (DWORD
*)dest
+ destWidth
* y
;
269 *d
++ = colour
[(b
[4 + y
] & 0x03)] | (a
[y
][0] << 24);
270 *d
++ = colour
[(b
[4 + y
] & 0x0e) >> 2] | (a
[y
][1] << 24);
271 *d
++ = colour
[(b
[4 + y
] & 0x30) >> 4] | (a
[y
][2] << 24);
272 *d
++ = colour
[(b
[4 + y
] & 0xe0) >> 6] | (a
[y
][3] << 24);
277 void ConvertDXT1(const void *src
, unsigned int width
, unsigned int height
, void *dest
)
279 for (unsigned int y
= 0; y
< height
; y
+= 4)
281 for (unsigned int x
= 0; x
< width
; x
+= 4)
283 const BYTE
*s
= (const BYTE
*)src
+ y
* width
/ 2 + x
* 2;
284 DWORD
*d
= (DWORD
*)dest
+ y
* width
+ x
;
285 DXT1toARGB(s
, d
, width
);
290 void ConvertDXT4(const void *src
, unsigned int width
, unsigned int height
, void *dest
)
292 // [4 4 4 4][4 4 4 4]
296 for (unsigned int y
= 0; y
< height
; y
+= 4)
298 for (unsigned int x
= 0; x
< width
; x
+= 4)
300 const BYTE
*s
= (const BYTE
*)src
+ y
* width
+ x
* 4;
301 DWORD
*d
= (DWORD
*)dest
+ y
* width
+ x
;
302 DXT4toARGB(s
, d
, width
);
307 void GetTextureFromData(D3DTexture
* pTex
, void* texData
, std::unique_ptr
<CTexture
>* ppTexture
)
310 DWORD width
, height
, pitch
, offset
;
311 ParseTextureHeader(pTex
, fmt
, width
, height
, pitch
, offset
);
313 *ppTexture
= CTexture::CreateTexture(width
, height
, XB_FMT_A8R8G8B8
);
317 BYTE
*texDataStart
= (BYTE
*)texData
;
318 COLOR
*color
= (COLOR
*)texData
;
319 texDataStart
+= offset
;
320 /* DXMERGE - We should really support DXT1,DXT2 and DXT4 in both renderers
321 Perhaps we should extend CTexture::Update() to support a bunch of different texture types
322 Rather than assuming linear 32bits
323 We could just override, as at least then all the loading code from various texture formats
326 BYTE *dstPixels = (BYTE *)lr.pBits;
327 DWORD destPitch = lr.Pitch;
328 if (fmt == XB_D3DFMT_DXT1) // Not sure if these are 100% correct, but they seem to work :P
333 else if (fmt == XB_D3DFMT_DXT2)
337 else if (fmt == XB_D3DFMT_DXT4)
343 if (fmt
== XB_D3DFMT_DXT1
)
346 BYTE
*decoded
= new BYTE
[pitch
* height
];
347 ConvertDXT1(texDataStart
, width
, height
, decoded
);
348 texDataStart
= decoded
;
350 else if (fmt
== XB_D3DFMT_DXT2
|| fmt
== XB_D3DFMT_DXT4
)
353 BYTE
*decoded
= new BYTE
[pitch
* height
];
354 ConvertDXT4(texDataStart
, width
, height
, decoded
);
355 texDataStart
= decoded
;
357 if (IsSwizzledFormat(fmt
))
358 { // first we unswizzle
359 BYTE
*unswizzled
= new BYTE
[pitch
* height
];
360 Unswizzle(texDataStart
, BytesPerPixelFromFormat(fmt
), width
, height
, unswizzled
);
361 texDataStart
= unswizzled
;
364 if (IsPalettedFormat(fmt
))
365 (*ppTexture
)->LoadPaletted(width
, height
, pitch
, XB_FMT_A8R8G8B8
, texDataStart
, color
);
367 (*ppTexture
)->LoadFromMemory(width
, height
, pitch
, XB_FMT_A8R8G8B8
, true, texDataStart
);
369 if (IsSwizzledFormat(fmt
) || fmt
== XB_D3DFMT_DXT1
|| fmt
== XB_D3DFMT_DXT2
|| fmt
== XB_D3DFMT_DXT4
)
371 delete[] texDataStart
;