1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2014-2018 - Ali Bouhlel
3  *
4  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
5  *  of the GNU General Public License as published by the Free Software Found-
6  *  ation, either version 3 of the License, or (at your option) any later version.
7  *
8  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10  *  PURPOSE.  See the GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License along with RetroArch.
13  *  If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 #include <compat/strl.h>
17 #include <string/stdstring.h>
18 #include <retro_environment.h>
19 
20 #include <assert.h>
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "dxgi_common.h"
27 #include "../../configuration.h"
28 #include "../../verbosity.h"
29 #include "../../ui/ui_companion_driver.h"
30 #include "../../retroarch.h"
31 #include "../frontend/frontend_driver.h"
32 #include "win32_common.h"
33 
34 #if defined(HAVE_DYNAMIC) && !defined(__WINRT__)
35 #include <dynamic/dylib.h>
36 
CreateDXGIFactory1(REFIID riid,void ** ppFactory)37 HRESULT WINAPI CreateDXGIFactory1(REFIID riid, void** ppFactory)
38 {
39    static HRESULT(WINAPI * fp)(REFIID, void**);
40 
41    static dylib_t dxgi_dll;
42 
43    if (!dxgi_dll)
44       dxgi_dll = dylib_load("dxgi.dll");
45 
46    if (!dxgi_dll)
47       return TYPE_E_CANTLOADLIBRARY;
48 
49    if (!fp)
50       fp = (HRESULT(WINAPI*)(REFIID, void**))dylib_proc(dxgi_dll, "CreateDXGIFactory1");
51 
52    if (!fp)
53       return TYPE_E_DLLFUNCTIONNOTFOUND;
54 
55    return fp(riid, ppFactory);
56 }
57 #endif
58 
dxgi_get_format_fallback_list(DXGI_FORMAT format)59 DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format)
60 {
61    switch ((unsigned)format)
62    {
63       case DXGI_FORMAT_R32G32B32A32_FLOAT:
64       {
65          static DXGI_FORMAT formats[] = { DXGI_FORMAT_R32G32B32A32_FLOAT,
66                                           DXGI_FORMAT_R16G16B16A16_FLOAT,
67                                           DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT,
68                                           DXGI_FORMAT_UNKNOWN };
69          return formats;
70       }
71       case DXGI_FORMAT_R16G16B16A16_FLOAT:
72       {
73          static DXGI_FORMAT formats[] = { DXGI_FORMAT_R16G16B16A16_FLOAT,
74                                           DXGI_FORMAT_R32G32B32A32_FLOAT,
75                                           DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT,
76                                           DXGI_FORMAT_UNKNOWN };
77          return formats;
78       }
79       case DXGI_FORMAT_R8G8B8A8_UNORM:
80       {
81          static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
82                                           DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_UNKNOWN };
83          return formats;
84       }
85       case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
86       {
87          static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
88                                           DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
89                                           DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_UNKNOWN };
90          return formats;
91       }
92       case DXGI_FORMAT_B8G8R8A8_UNORM:
93       {
94          static DXGI_FORMAT formats[] = { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
95                                           DXGI_FORMAT_UNKNOWN };
96          return formats;
97       }
98       case DXGI_FORMAT_B8G8R8X8_UNORM:
99       {
100          static DXGI_FORMAT formats[] = { DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
101                                           DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN };
102          return formats;
103       }
104       case DXGI_FORMAT_B5G6R5_UNORM:
105       {
106          static DXGI_FORMAT formats[] = { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B8G8R8X8_UNORM,
107                                           DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
108                                           DXGI_FORMAT_UNKNOWN };
109          return formats;
110       }
111       case DXGI_FORMAT_EX_A4R4G4B4_UNORM:
112       case DXGI_FORMAT_B4G4R4A4_UNORM:
113       {
114          static DXGI_FORMAT formats[] = { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
115                                           DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN };
116          return formats;
117       }
118       case DXGI_FORMAT_A8_UNORM:
119       {
120          static DXGI_FORMAT formats[] = { DXGI_FORMAT_A8_UNORM,       DXGI_FORMAT_R8_UNORM,
121                                           DXGI_FORMAT_R8G8_UNORM,     DXGI_FORMAT_R8G8B8A8_UNORM,
122                                           DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN };
123          return formats;
124       }
125       case DXGI_FORMAT_R8_UNORM:
126       {
127          static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8_UNORM,       DXGI_FORMAT_A8_UNORM,
128                                           DXGI_FORMAT_R8G8_UNORM,     DXGI_FORMAT_R8G8B8A8_UNORM,
129                                           DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN };
130          return formats;
131       }
132       default:
133          break;
134    }
135    return NULL;
136 }
137 
138 #define FORMAT_PROCESS_( \
139       src_type, src_rb, src_gb, src_bb, src_ab, src_rs, src_gs, src_bs, src_as, dst_type, dst_rb, \
140       dst_gb, dst_bb, dst_ab, dst_rs, dst_gs, dst_bs, dst_as) \
141    do \
142    { \
143       if ((sizeof(src_type) == sizeof(dst_type)) && \
144           ((src_rs == dst_rs && src_rb == dst_rb) || !dst_rb) && \
145           ((src_gs == dst_gs && src_gb == dst_gb) || !dst_gb) && \
146           ((src_bs == dst_bs && src_bb == dst_bb) || !dst_bb) && \
147           ((src_as == dst_as && src_ab == dst_ab) || !dst_ab)) \
148       { \
149          const UINT8* in  = (const UINT8*)src_data; \
150          UINT8*       out = (UINT8*)dst_data; \
151          for (i = 0; i < height; i++) \
152          { \
153             memcpy(out, in, width * sizeof(src_type)); \
154             in += src_pitch ? src_pitch : width * sizeof(src_type); \
155             out += dst_pitch ? dst_pitch : width * sizeof(dst_type); \
156          } \
157       } \
158       else \
159       { \
160          const src_type* src_ptr = (const src_type*)src_data; \
161          dst_type*       dst_ptr = (dst_type*)dst_data; \
162          if (src_pitch) \
163             src_pitch -= width * sizeof(*src_ptr); \
164          if (dst_pitch) \
165             dst_pitch -= width * sizeof(*dst_ptr); \
166          for (i = 0; i < height; i++) \
167          { \
168             for (j = 0; j < width; j++) \
169             { \
170                unsigned r, g, b, a; \
171                src_type src_val = *src_ptr++; \
172                if (src_rb) \
173                { \
174                   r = (src_val >> src_rs) & ((1 << src_rb) - 1); \
175                   r = (src_rb < dst_rb) \
176                             ? (r << (dst_rb - src_rb)) | \
177                                     (r >> ((2 * src_rb > dst_rb) ? 2 * src_rb - dst_rb : 0)) \
178                             : r >> (src_rb - dst_rb); \
179                } \
180                if (src_gb) \
181                { \
182                   g = (src_val >> src_gs) & ((1 << src_gb) - 1); \
183                   g = (src_gb < dst_gb) \
184                             ? (g << (dst_gb - src_gb)) | \
185                                     (g >> ((2 * src_gb > dst_gb) ? 2 * src_gb - dst_gb : 0)) \
186                             : g >> (src_gb - dst_gb); \
187                } \
188                if (src_bb) \
189                { \
190                   b = (src_val >> src_bs) & ((1 << src_bb) - 1); \
191                   b = (src_bb < dst_bb) \
192                             ? (b << (dst_bb - src_bb)) | \
193                                     (b >> ((2 * src_bb > dst_bb) ? 2 * src_bb - dst_bb : 0)) \
194                             : b >> (src_bb - dst_bb); \
195                } \
196                if (src_ab) \
197                { \
198                   a = (src_val >> src_as) & ((1 << src_ab) - 1); \
199                   a = (src_ab < dst_ab) \
200                             ? (a << (dst_ab - src_ab)) | \
201                                     (a >> ((2 * src_ab > dst_ab) ? 2 * src_ab - dst_ab : 0)) \
202                             : a >> (src_ab - dst_ab); \
203                } \
204                *dst_ptr++ = ((src_rb ? r : 0) << dst_rs) | ((src_gb ? g : 0) << dst_gs) | \
205                             ((src_bb ? b : 0) << dst_bs) | \
206                             ((src_ab ? a : ((1 << dst_ab) - 1)) << dst_as); \
207             } \
208             src_ptr = (src_type*)((UINT8*)src_ptr + src_pitch); \
209             dst_ptr = (dst_type*)((UINT8*)dst_ptr + dst_pitch); \
210          } \
211       } \
212    } while (0)
213 
214 #define FORMAT_PROCESS(args) FORMAT_PROCESS_ args
215 
216 #define FORMAT_DST(st, dt) \
217    case dt: \
218    { \
219       FORMAT_PROCESS((st##_DESCS, dt##_DESCS)); \
220       break; \
221    }
222 
223 #define FORMAT_SRC(st) \
224    case st: \
225    { \
226       switch ((unsigned)dst_format) \
227       { \
228          FORMAT_DST_LIST(st); \
229          default: \
230             assert(0); \
231             break; \
232       } \
233       break; \
234    }
235 
236 /* clang-format off */
237 /*                                                        r, g, b, a,     r,  g,  b,  a */
238 #define DXGI_FORMAT_R8G8B8A8_UNORM_DESCS       UINT32,    8, 8, 8, 8,     0,  8, 16, 24
239 #define DXGI_FORMAT_B8G8R8X8_UNORM_DESCS       UINT32,    8, 8, 8, 0,    16,  8,  0,  0
240 #define DXGI_FORMAT_B8G8R8A8_UNORM_DESCS       UINT32,    8, 8, 8, 8,    16,  8,  0, 24
241 #define DXGI_FORMAT_A8_UNORM_DESCS             UINT8,     0, 0, 0, 8,     0,  0,  0,  0
242 #define DXGI_FORMAT_R8_UNORM_DESCS             UINT8,     8, 0, 0, 0,     0,  0,  0,  0
243 #define DXGI_FORMAT_B5G6R5_UNORM_DESCS         UINT16,    5, 6, 5, 0,    11,  5,  0,  0
244 #define DXGI_FORMAT_B5G5R5A1_UNORM_DESCS       UINT16,    5, 5, 5, 1,    10,  5,  0, 11
245 #define DXGI_FORMAT_B4G4R4A4_UNORM_DESCS       UINT16,    4, 4, 4, 4,     8,  4,  0, 12
246 #define DXGI_FORMAT_EX_A4R4G4B4_UNORM_DESCS    UINT16,    4, 4, 4, 4,     4,  8, 12,  0
247 
248 #define FORMAT_SRC_LIST() \
249    FORMAT_SRC(DXGI_FORMAT_R8G8B8A8_UNORM); \
250    FORMAT_SRC(DXGI_FORMAT_B8G8R8X8_UNORM); \
251    FORMAT_SRC(DXGI_FORMAT_A8_UNORM); \
252    FORMAT_SRC(DXGI_FORMAT_R8_UNORM); \
253    FORMAT_SRC(DXGI_FORMAT_B5G6R5_UNORM); \
254    FORMAT_SRC(DXGI_FORMAT_B5G5R5A1_UNORM); \
255    FORMAT_SRC(DXGI_FORMAT_B4G4R4A4_UNORM); \
256    FORMAT_SRC(DXGI_FORMAT_B8G8R8A8_UNORM); \
257    FORMAT_SRC(DXGI_FORMAT_EX_A4R4G4B4_UNORM)
258 
259 #define FORMAT_DST_LIST(srcfmt) \
260    FORMAT_DST(srcfmt, DXGI_FORMAT_R8G8B8A8_UNORM); \
261    FORMAT_DST(srcfmt, DXGI_FORMAT_B8G8R8X8_UNORM); \
262    FORMAT_DST(srcfmt, DXGI_FORMAT_A8_UNORM); \
263    FORMAT_DST(srcfmt, DXGI_FORMAT_R8_UNORM); \
264    FORMAT_DST(srcfmt, DXGI_FORMAT_B5G6R5_UNORM); \
265    FORMAT_DST(srcfmt, DXGI_FORMAT_B5G5R5A1_UNORM); \
266    FORMAT_DST(srcfmt, DXGI_FORMAT_B4G4R4A4_UNORM); \
267    FORMAT_DST(srcfmt, DXGI_FORMAT_B8G8R8A8_UNORM); \
268    FORMAT_DST(srcfmt, DXGI_FORMAT_EX_A4R4G4B4_UNORM)
269    /* clang-format on */
270 
271 #ifdef _MSC_VER
272 #pragma warning(disable : 4293)
273 #endif
dxgi_copy(int width,int height,DXGI_FORMAT src_format,int src_pitch,const void * src_data,DXGI_FORMAT dst_format,int dst_pitch,void * dst_data)274 void dxgi_copy(
275       int         width,
276       int         height,
277       DXGI_FORMAT src_format,
278       int         src_pitch,
279       const void* src_data,
280       DXGI_FORMAT dst_format,
281       int         dst_pitch,
282       void*       dst_data)
283 {
284    int i, j;
285 
286    switch ((unsigned)src_format)
287    {
288       FORMAT_SRC_LIST();
289 
290       default:
291       assert(0);
292       break;
293    }
294 }
295 
296 #ifdef _MSC_VER
297 #pragma warning(default : 4293)
298 #endif
299 
glslang_format_to_dxgi(glslang_format fmt)300 DXGI_FORMAT glslang_format_to_dxgi(glslang_format fmt)
301 {
302 #undef FMT_
303 #define FMT_(x)  case SLANG_FORMAT_##x: return DXGI_FORMAT_##x
304 #undef FMT2
305 #define FMT2(x,y) case SLANG_FORMAT_##x: return y
306 
307    switch (fmt)
308    {
309    FMT_(R8_UNORM);
310    FMT_(R8_SINT);
311    FMT_(R8_UINT);
312    FMT_(R8G8_UNORM);
313    FMT_(R8G8_SINT);
314    FMT_(R8G8_UINT);
315    FMT_(R8G8B8A8_UNORM);
316    FMT_(R8G8B8A8_SINT);
317    FMT_(R8G8B8A8_UINT);
318    FMT2(R8G8B8A8_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
319 
320    FMT2(A2B10G10R10_UNORM_PACK32, DXGI_FORMAT_R10G10B10A2_UNORM);
321    FMT2(A2B10G10R10_UINT_PACK32, DXGI_FORMAT_R10G10B10A2_UNORM);
322 
323    FMT_(R16_UINT);
324    FMT_(R16_SINT);
325    FMT2(R16_SFLOAT, DXGI_FORMAT_R16_FLOAT);
326    FMT_(R16G16_UINT);
327    FMT_(R16G16_SINT);
328    FMT2(R16G16_SFLOAT, DXGI_FORMAT_R16G16_FLOAT);
329    FMT_(R16G16B16A16_UINT);
330    FMT_(R16G16B16A16_SINT);
331    FMT2(R16G16B16A16_SFLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT);
332 
333    FMT_(R32_UINT);
334    FMT_(R32_SINT);
335    FMT2(R32_SFLOAT, DXGI_FORMAT_R32_FLOAT);
336    FMT_(R32G32_UINT);
337    FMT_(R32G32_SINT);
338    FMT2(R32G32_SFLOAT, DXGI_FORMAT_R32G32_FLOAT);
339    FMT_(R32G32B32A32_UINT);
340    FMT_(R32G32B32A32_SINT);
341    FMT2(R32G32B32A32_SFLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT);
342 
343    case SLANG_FORMAT_UNKNOWN:
344    default:
345       break;
346    }
347 
348    return DXGI_FORMAT_UNKNOWN;
349 }
350