mirror of
https://github.com/libretro/RetroArch.git
synced 2024-11-28 02:30:35 +00:00
4c3a4d66df
* CXX_BUILD buildfixes * (D3D11) Buildfixes for CXX_BUILD * (Linux/qb) Disable KMS for Linux when building for C89, headers use inline which is not available for C89
728 lines
24 KiB
C
728 lines
24 KiB
C
/* RetroArch - A frontend for libretro.
|
|
* Copyright (C) 2014-2018 - Ali Bouhlel
|
|
*
|
|
* RetroArch is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with RetroArch.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <compat/strl.h>
|
|
#include <string/stdstring.h>
|
|
#include <retro_environment.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "../../config.h"
|
|
#endif
|
|
|
|
#include "win32_common.h"
|
|
#include "dxgi_common.h"
|
|
#include "../../configuration.h"
|
|
#include "../../verbosity.h"
|
|
#include "../../ui/ui_companion_driver.h"
|
|
#include "../../retroarch.h"
|
|
#include "../frontend/frontend_driver.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern const GUID DECLSPEC_SELECTANY libretro_IID_IDXGIOutput6 = { 0x068346e8,0xaaec,
|
|
0x4b84, {0xad,0xd7,0x13,0x7f,0x51,0x3f,0x77,0xa1 } };
|
|
#else
|
|
const GUID DECLSPEC_SELECTANY libretro_IID_IDXGIOutput6 = { 0x068346e8,0xaaec,
|
|
0x4b84, {0xad,0xd7,0x13,0x7f,0x51,0x3f,0x77,0xa1 } };
|
|
#endif
|
|
|
|
#ifdef HAVE_DXGI_HDR
|
|
/* TODO/FIXME - globals */
|
|
static DXGI_HDR_METADATA_HDR10 g_hdr10_meta_data = {0};
|
|
|
|
typedef enum hdr_root_constants
|
|
{
|
|
HDR_ROOT_CONSTANTS_REFERENCE_WHITE_NITS = 0,
|
|
HDR_ROOT_CONSTANTS_DISPLAY_CURVE,
|
|
HDR_ROOT_CONSTANTS_COUNT
|
|
} hdr_root_constants_t;
|
|
#endif
|
|
|
|
#if defined(HAVE_DYNAMIC) && !defined(__WINRT__)
|
|
#include <dynamic/dylib.h>
|
|
|
|
HRESULT WINAPI CreateDXGIFactory1(REFIID riid, void** ppFactory)
|
|
{
|
|
static HRESULT(WINAPI * fp)(REFIID, void**);
|
|
|
|
static dylib_t dxgi_dll;
|
|
|
|
if (!dxgi_dll)
|
|
dxgi_dll = dylib_load("dxgi.dll");
|
|
|
|
if (!dxgi_dll)
|
|
return TYPE_E_CANTLOADLIBRARY;
|
|
|
|
if (!fp)
|
|
fp = (HRESULT(WINAPI*)(REFIID, void**))dylib_proc(dxgi_dll, "CreateDXGIFactory1");
|
|
|
|
if (!fp)
|
|
return TYPE_E_DLLFUNCTIONNOTFOUND;
|
|
|
|
return fp(riid, ppFactory);
|
|
}
|
|
#endif
|
|
|
|
DXGI_FORMAT* dxgi_get_format_fallback_list(DXGI_FORMAT format)
|
|
{
|
|
switch ((unsigned)format)
|
|
{
|
|
case DXGI_FORMAT_R32G32B32A32_FLOAT:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_R32G32B32A32_FLOAT,
|
|
DXGI_FORMAT_R16G16B16A16_FLOAT,
|
|
DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT,
|
|
DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_R16G16B16A16_FLOAT,
|
|
DXGI_FORMAT_R32G32B32A32_FLOAT,
|
|
DXGI_FORMAT_R32G32B32_FLOAT, DXGI_FORMAT_R11G11B10_FLOAT,
|
|
DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
|
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_B8G8R8A8_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_B8G8R8X8_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_B5G6R5_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_B5G6R5_UNORM, DXGI_FORMAT_B8G8R8X8_UNORM,
|
|
DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_EX_A4R4G4B4_UNORM:
|
|
case DXGI_FORMAT_B4G4R4A4_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_B4G4R4A4_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM,
|
|
DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_A8_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_R8_UNORM,
|
|
DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
case DXGI_FORMAT_R8_UNORM:
|
|
{
|
|
static DXGI_FORMAT formats[] = { DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_A8_UNORM,
|
|
DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_UNKNOWN };
|
|
return formats;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
#define FORMAT_PROCESS_( \
|
|
src_type, src_rb, src_gb, src_bb, src_ab, src_rs, src_gs, src_bs, src_as, dst_type, dst_rb, \
|
|
dst_gb, dst_bb, dst_ab, dst_rs, dst_gs, dst_bs, dst_as) \
|
|
do \
|
|
{ \
|
|
if ((sizeof(src_type) == sizeof(dst_type)) && \
|
|
((src_rs == dst_rs && src_rb == dst_rb) || !dst_rb) && \
|
|
((src_gs == dst_gs && src_gb == dst_gb) || !dst_gb) && \
|
|
((src_bs == dst_bs && src_bb == dst_bb) || !dst_bb) && \
|
|
((src_as == dst_as && src_ab == dst_ab) || !dst_ab)) \
|
|
{ \
|
|
const UINT8* in = (const UINT8*)src_data; \
|
|
UINT8* out = (UINT8*)dst_data; \
|
|
for (i = 0; i < height; i++) \
|
|
{ \
|
|
memcpy(out, in, width * sizeof(src_type)); \
|
|
in += src_pitch ? src_pitch : width * sizeof(src_type); \
|
|
out += dst_pitch ? dst_pitch : width * sizeof(dst_type); \
|
|
} \
|
|
} \
|
|
else \
|
|
{ \
|
|
const src_type* src_ptr = (const src_type*)src_data; \
|
|
dst_type* dst_ptr = (dst_type*)dst_data; \
|
|
if (src_pitch) \
|
|
src_pitch -= width * sizeof(*src_ptr); \
|
|
if (dst_pitch) \
|
|
dst_pitch -= width * sizeof(*dst_ptr); \
|
|
for (i = 0; i < height; i++) \
|
|
{ \
|
|
for (j = 0; j < width; j++) \
|
|
{ \
|
|
unsigned r, g, b, a; \
|
|
src_type src_val = *src_ptr++; \
|
|
if (src_rb) \
|
|
{ \
|
|
r = (src_val >> src_rs) & ((1 << src_rb) - 1); \
|
|
r = (src_rb < dst_rb) \
|
|
? (r << (dst_rb - src_rb)) | \
|
|
(r >> ((2 * src_rb > dst_rb) ? 2 * src_rb - dst_rb : 0)) \
|
|
: r >> (src_rb - dst_rb); \
|
|
} \
|
|
if (src_gb) \
|
|
{ \
|
|
g = (src_val >> src_gs) & ((1 << src_gb) - 1); \
|
|
g = (src_gb < dst_gb) \
|
|
? (g << (dst_gb - src_gb)) | \
|
|
(g >> ((2 * src_gb > dst_gb) ? 2 * src_gb - dst_gb : 0)) \
|
|
: g >> (src_gb - dst_gb); \
|
|
} \
|
|
if (src_bb) \
|
|
{ \
|
|
b = (src_val >> src_bs) & ((1 << src_bb) - 1); \
|
|
b = (src_bb < dst_bb) \
|
|
? (b << (dst_bb - src_bb)) | \
|
|
(b >> ((2 * src_bb > dst_bb) ? 2 * src_bb - dst_bb : 0)) \
|
|
: b >> (src_bb - dst_bb); \
|
|
} \
|
|
if (src_ab) \
|
|
{ \
|
|
a = (src_val >> src_as) & ((1 << src_ab) - 1); \
|
|
a = (src_ab < dst_ab) \
|
|
? (a << (dst_ab - src_ab)) | \
|
|
(a >> ((2 * src_ab > dst_ab) ? 2 * src_ab - dst_ab : 0)) \
|
|
: a >> (src_ab - dst_ab); \
|
|
} \
|
|
*dst_ptr++ = ((src_rb ? r : 0) << dst_rs) | ((src_gb ? g : 0) << dst_gs) | \
|
|
((src_bb ? b : 0) << dst_bs) | \
|
|
((src_ab ? a : ((1 << dst_ab) - 1)) << dst_as); \
|
|
} \
|
|
src_ptr = (src_type*)((UINT8*)src_ptr + src_pitch); \
|
|
dst_ptr = (dst_type*)((UINT8*)dst_ptr + dst_pitch); \
|
|
} \
|
|
} \
|
|
} while (0)
|
|
|
|
#define FORMAT_PROCESS(args) FORMAT_PROCESS_ args
|
|
|
|
#define FORMAT_DST(st, dt) \
|
|
case dt: \
|
|
{ \
|
|
FORMAT_PROCESS((st##_DESCS, dt##_DESCS)); \
|
|
break; \
|
|
}
|
|
|
|
#define FORMAT_SRC(st) \
|
|
case st: \
|
|
{ \
|
|
switch ((unsigned)dst_format) \
|
|
{ \
|
|
FORMAT_DST_LIST(st); \
|
|
default: \
|
|
assert(0); \
|
|
break; \
|
|
} \
|
|
break; \
|
|
}
|
|
|
|
/* clang-format off */
|
|
/* r, g, b, a, r, g, b, a */
|
|
#define DXGI_FORMAT_R8G8B8A8_UNORM_DESCS UINT32, 8, 8, 8, 8, 0, 8, 16, 24
|
|
#define DXGI_FORMAT_B8G8R8X8_UNORM_DESCS UINT32, 8, 8, 8, 0, 16, 8, 0, 0
|
|
#define DXGI_FORMAT_B8G8R8A8_UNORM_DESCS UINT32, 8, 8, 8, 8, 16, 8, 0, 24
|
|
#define DXGI_FORMAT_A8_UNORM_DESCS UINT8, 0, 0, 0, 8, 0, 0, 0, 0
|
|
#define DXGI_FORMAT_R8_UNORM_DESCS UINT8, 8, 0, 0, 0, 0, 0, 0, 0
|
|
#define DXGI_FORMAT_B5G6R5_UNORM_DESCS UINT16, 5, 6, 5, 0, 11, 5, 0, 0
|
|
#define DXGI_FORMAT_B5G5R5A1_UNORM_DESCS UINT16, 5, 5, 5, 1, 10, 5, 0, 11
|
|
#define DXGI_FORMAT_B4G4R4A4_UNORM_DESCS UINT16, 4, 4, 4, 4, 8, 4, 0, 12
|
|
#define DXGI_FORMAT_EX_A4R4G4B4_UNORM_DESCS UINT16, 4, 4, 4, 4, 4, 8, 12, 0
|
|
|
|
#define FORMAT_SRC_LIST() \
|
|
FORMAT_SRC(DXGI_FORMAT_R8G8B8A8_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_B8G8R8X8_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_A8_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_R8_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_B5G6R5_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_B5G5R5A1_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_B4G4R4A4_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_B8G8R8A8_UNORM); \
|
|
FORMAT_SRC(DXGI_FORMAT_EX_A4R4G4B4_UNORM)
|
|
|
|
#define FORMAT_DST_LIST(srcfmt) \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_R8G8B8A8_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_B8G8R8X8_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_A8_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_R8_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_B5G6R5_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_B5G5R5A1_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_B4G4R4A4_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_B8G8R8A8_UNORM); \
|
|
FORMAT_DST(srcfmt, DXGI_FORMAT_EX_A4R4G4B4_UNORM)
|
|
/* clang-format on */
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(disable : 4293)
|
|
#endif
|
|
void 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)
|
|
{
|
|
int i, j;
|
|
|
|
switch ((unsigned)src_format)
|
|
{
|
|
FORMAT_SRC_LIST();
|
|
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning(default : 4293)
|
|
#endif
|
|
|
|
DXGI_FORMAT glslang_format_to_dxgi(glslang_format fmt)
|
|
{
|
|
#undef FMT_
|
|
#define FMT_(x) case SLANG_FORMAT_##x: return DXGI_FORMAT_##x
|
|
#undef FMT2
|
|
#define FMT2(x,y) case SLANG_FORMAT_##x: return y
|
|
|
|
switch (fmt)
|
|
{
|
|
FMT_(R8_UNORM);
|
|
FMT_(R8_SINT);
|
|
FMT_(R8_UINT);
|
|
FMT_(R8G8_UNORM);
|
|
FMT_(R8G8_SINT);
|
|
FMT_(R8G8_UINT);
|
|
FMT_(R8G8B8A8_UNORM);
|
|
FMT_(R8G8B8A8_SINT);
|
|
FMT_(R8G8B8A8_UINT);
|
|
FMT2(R8G8B8A8_SRGB, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
|
|
|
|
FMT2(A2B10G10R10_UNORM_PACK32, DXGI_FORMAT_R10G10B10A2_UNORM);
|
|
FMT2(A2B10G10R10_UINT_PACK32, DXGI_FORMAT_R10G10B10A2_UNORM);
|
|
|
|
FMT_(R16_UINT);
|
|
FMT_(R16_SINT);
|
|
FMT2(R16_SFLOAT, DXGI_FORMAT_R16_FLOAT);
|
|
FMT_(R16G16_UINT);
|
|
FMT_(R16G16_SINT);
|
|
FMT2(R16G16_SFLOAT, DXGI_FORMAT_R16G16_FLOAT);
|
|
FMT_(R16G16B16A16_UINT);
|
|
FMT_(R16G16B16A16_SINT);
|
|
FMT2(R16G16B16A16_SFLOAT, DXGI_FORMAT_R16G16B16A16_FLOAT);
|
|
|
|
FMT_(R32_UINT);
|
|
FMT_(R32_SINT);
|
|
FMT2(R32_SFLOAT, DXGI_FORMAT_R32_FLOAT);
|
|
FMT_(R32G32_UINT);
|
|
FMT_(R32G32_SINT);
|
|
FMT2(R32G32_SFLOAT, DXGI_FORMAT_R32G32_FLOAT);
|
|
FMT_(R32G32B32A32_UINT);
|
|
FMT_(R32G32B32A32_SINT);
|
|
FMT2(R32G32B32A32_SFLOAT, DXGI_FORMAT_R32G32B32A32_FLOAT);
|
|
|
|
case SLANG_FORMAT_UNKNOWN:
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return DXGI_FORMAT_UNKNOWN;
|
|
}
|
|
|
|
#ifdef HAVE_DXGI_HDR
|
|
typedef struct display_chromaticities
|
|
{
|
|
float red_x;
|
|
float red_y;
|
|
float green_x;
|
|
float green_y;
|
|
float blue_x;
|
|
float blue_y;
|
|
float white_x;
|
|
float white_y;
|
|
} display_chromaticities_t;
|
|
|
|
inline static int dxgi_compute_intersection_area(
|
|
int ax1, int ay1, int ax2, int ay2,
|
|
int bx1, int by1, int bx2, int by2)
|
|
{
|
|
return MAX(0, MIN(ax2, bx2) -
|
|
MAX(ax1, bx1))
|
|
* MAX(0, MIN(ay2, by2) - MAX(ay1, by1));
|
|
}
|
|
|
|
#ifdef __WINRT__
|
|
bool dxgi_check_display_hdr_support(DXGIFactory2 factory, HWND hwnd)
|
|
#else
|
|
bool dxgi_check_display_hdr_support(DXGIFactory factory, HWND hwnd)
|
|
#endif
|
|
{
|
|
DXGIOutput6 output6 = NULL;
|
|
DXGIOutput best_output = NULL;
|
|
DXGIOutput current_output = NULL;
|
|
DXGIAdapter dxgi_adapter = NULL;
|
|
UINT i = 0;
|
|
bool supported = false;
|
|
float best_intersect_area = -1;
|
|
|
|
#ifdef __WINRT__
|
|
#ifdef __cplusplus
|
|
if (!factory->IsCurrent())
|
|
#else
|
|
if (!factory->lpVtbl->IsCurrent(factory))
|
|
#endif
|
|
{
|
|
if (FAILED(DXGICreateFactory2(&factory)))
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to create DXGI factory\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
if (FAILED(factory->EnumAdapters1(0, &dxgi_adapter)))
|
|
#else
|
|
if (FAILED(factory->lpVtbl->EnumAdapters1(factory, 0, &dxgi_adapter)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to enumerate adapters\n");
|
|
return false;
|
|
}
|
|
#else
|
|
#ifdef __cplusplus
|
|
if (!factory->IsCurrent())
|
|
#else
|
|
if (!factory->lpVtbl->IsCurrent(factory))
|
|
#endif
|
|
{
|
|
if (FAILED(DXGICreateFactory(&factory)))
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to create DXGI factory\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
if (FAILED(factory->EnumAdapters1(0, &dxgi_adapter)))
|
|
#else
|
|
if (FAILED(factory->lpVtbl->EnumAdapters1(factory, 0, &dxgi_adapter)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to enumerate adapters\n");
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
while ( dxgi_adapter->EnumOutputs(i, ¤t_output)
|
|
!= DXGI_ERROR_NOT_FOUND)
|
|
#else
|
|
while ( dxgi_adapter->lpVtbl->EnumOutputs(dxgi_adapter, i, ¤t_output)
|
|
!= DXGI_ERROR_NOT_FOUND)
|
|
#endif
|
|
{
|
|
RECT r, rect;
|
|
DXGI_OUTPUT_DESC desc;
|
|
int intersect_area;
|
|
int bx1, by1, bx2, by2;
|
|
int ax1 = 0;
|
|
int ay1 = 0;
|
|
int ax2 = 0;
|
|
int ay2 = 0;
|
|
|
|
if (win32_get_client_rect(&rect))
|
|
{
|
|
ax1 = rect.left;
|
|
ay1 = rect.top;
|
|
ax2 = rect.right;
|
|
ay2 = rect.bottom;
|
|
}
|
|
|
|
/* Get the rectangle bounds of current output */
|
|
#ifdef __cplusplus
|
|
if (FAILED(current_output->GetDesc(&desc)))
|
|
#else
|
|
if (FAILED(current_output->lpVtbl->GetDesc(current_output, &desc)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to get DXGI output description\n");
|
|
goto error;
|
|
}
|
|
|
|
/* TODO/FIXME - DesktopCoordinates won't work for WinRT */
|
|
r = desc.DesktopCoordinates;
|
|
bx1 = r.left;
|
|
by1 = r.top;
|
|
bx2 = r.right;
|
|
by2 = r.bottom;
|
|
|
|
/* Compute the intersection */
|
|
intersect_area = dxgi_compute_intersection_area(
|
|
ax1, ay1, ax2, ay2, bx1, by1, bx2, by2);
|
|
|
|
if (intersect_area > best_intersect_area)
|
|
{
|
|
best_output = current_output;
|
|
#if defined(__cplusplus)
|
|
best_output->AddRef();
|
|
#else
|
|
AddRef(best_output);
|
|
#endif
|
|
best_intersect_area = (float)intersect_area;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
if (SUCCEEDED(best_output->QueryInterface(
|
|
libretro_IID_IDXGIOutput6, (void**)&output6)))
|
|
#else
|
|
if (SUCCEEDED(best_output->lpVtbl->QueryInterface(
|
|
best_output,
|
|
&libretro_IID_IDXGIOutput6, (void**)&output6)))
|
|
#endif
|
|
{
|
|
DXGI_OUTPUT_DESC1 desc1;
|
|
#ifdef __cplusplus
|
|
if (SUCCEEDED(output6->GetDesc1(&desc1)))
|
|
#else
|
|
if (SUCCEEDED(output6->lpVtbl->GetDesc1(output6, &desc1)))
|
|
#endif
|
|
{
|
|
supported = (desc1.ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020);
|
|
|
|
if (supported)
|
|
video_driver_set_hdr_support();
|
|
else
|
|
{
|
|
settings_t* settings = config_get_ptr();
|
|
settings->modified = true;
|
|
settings->bools.video_hdr_enable = false;
|
|
|
|
video_driver_unset_hdr_support();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to get DXGI Output 6 description\n");
|
|
}
|
|
#ifdef __cplusplus
|
|
output6->Release();
|
|
#else
|
|
Release(output6);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to get DXGI Output 6 from best output\n");
|
|
}
|
|
|
|
error:
|
|
#ifdef __cplusplus
|
|
best_output->Release();
|
|
current_output->Release();
|
|
dxgi_adapter->Release();
|
|
#else
|
|
Release(best_output);
|
|
Release(current_output);
|
|
Release(dxgi_adapter);
|
|
#endif
|
|
|
|
return supported;
|
|
}
|
|
|
|
void dxgi_swapchain_color_space(
|
|
DXGISwapChain chain_handle,
|
|
DXGI_COLOR_SPACE_TYPE *chain_color_space,
|
|
DXGI_COLOR_SPACE_TYPE color_space)
|
|
{
|
|
if (*chain_color_space != color_space)
|
|
{
|
|
UINT color_space_support = 0;
|
|
#ifdef __cplusplus
|
|
if (SUCCEEDED(chain_handle->CheckColorSpaceSupport(
|
|
color_space, &color_space_support))
|
|
&& ((color_space_support &
|
|
DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
|
|
== DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
|
#else
|
|
if (SUCCEEDED(chain_handle->lpVtbl->CheckColorSpaceSupport(
|
|
chain_handle, color_space, &color_space_support))
|
|
&& ((color_space_support &
|
|
DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
|
|
== DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT))
|
|
#endif
|
|
{
|
|
#ifdef __cplusplus
|
|
if (FAILED(chain_handle->SetColorSpace1(color_space)))
|
|
#else
|
|
if (FAILED(chain_handle->lpVtbl->SetColorSpace1(chain_handle, color_space)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to set DXGI swapchain colour space\n");
|
|
/* TODO/FIXME/CLARIFICATION: Was this fall-through intentional?
|
|
* Should chain color space still be set even when this fails?
|
|
* Going to assume this was wrong and early return instead
|
|
*/
|
|
return;
|
|
}
|
|
|
|
*chain_color_space = color_space;
|
|
}
|
|
}
|
|
}
|
|
|
|
void dxgi_set_hdr_metadata(
|
|
DXGISwapChain handle,
|
|
bool hdr_supported,
|
|
enum dxgi_swapchain_bit_depth chain_bit_depth,
|
|
DXGI_COLOR_SPACE_TYPE chain_color_space,
|
|
float max_output_nits,
|
|
float min_output_nits,
|
|
float max_cll,
|
|
float max_fall
|
|
)
|
|
{
|
|
static const display_chromaticities_t
|
|
display_chromaticity_list[] =
|
|
{
|
|
{ 0.64000f, 0.33000f, 0.30000f, 0.60000f, 0.15000f, 0.06000f, 0.31270f, 0.32900f }, /* Rec709 */
|
|
{ 0.70800f, 0.29200f, 0.17000f, 0.79700f, 0.13100f, 0.04600f, 0.31270f, 0.32900f }, /* Rec2020 */
|
|
};
|
|
const display_chromaticities_t* chroma = NULL;
|
|
DXGI_HDR_METADATA_HDR10 hdr10_meta_data = {0};
|
|
int selected_chroma = 0;
|
|
|
|
if (!handle)
|
|
return;
|
|
|
|
/* Clear the hdr meta data if the monitor does not support HDR */
|
|
if (!hdr_supported)
|
|
{
|
|
#ifdef __cplusplus
|
|
if (FAILED(handle->SetHDRMetaData(
|
|
DXGI_HDR_METADATA_TYPE_NONE, 0, NULL)))
|
|
#else
|
|
if (FAILED(handle->lpVtbl->SetHDRMetaData(handle,
|
|
DXGI_HDR_METADATA_TYPE_NONE, 0, NULL)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to set HDR meta data to none\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/* Now select the chromacity based on colour space */
|
|
if ( chain_bit_depth == DXGI_SWAPCHAIN_BIT_DEPTH_10
|
|
&& chain_color_space ==
|
|
DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
|
|
selected_chroma = 1;
|
|
else
|
|
{
|
|
#ifdef __cplusplus
|
|
if (FAILED(handle->SetHDRMetaData(
|
|
DXGI_HDR_METADATA_TYPE_NONE, 0, NULL)))
|
|
#else
|
|
if (FAILED(handle->lpVtbl->SetHDRMetaData(handle,
|
|
DXGI_HDR_METADATA_TYPE_NONE, 0, NULL)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to set HDR meta data to none\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* Set the HDR meta data */
|
|
chroma =
|
|
&display_chromaticity_list[selected_chroma];
|
|
hdr10_meta_data.RedPrimary[0] =
|
|
(UINT16)(chroma->red_x * 50000.0f);
|
|
hdr10_meta_data.RedPrimary[1] =
|
|
(UINT16)(chroma->red_y * 50000.0f);
|
|
hdr10_meta_data.GreenPrimary[0] =
|
|
(UINT16)(chroma->green_x * 50000.0f);
|
|
hdr10_meta_data.GreenPrimary[1] =
|
|
(UINT16)(chroma->green_y * 50000.0f);
|
|
hdr10_meta_data.BluePrimary[0] =
|
|
(UINT16)(chroma->blue_x * 50000.0f);
|
|
hdr10_meta_data.BluePrimary[1] =
|
|
(UINT16)(chroma->blue_y * 50000.0f);
|
|
hdr10_meta_data.WhitePoint[0] =
|
|
(UINT16)(chroma->white_x * 50000.0f);
|
|
hdr10_meta_data.WhitePoint[1] =
|
|
(UINT16)(chroma->white_y * 50000.0f);
|
|
hdr10_meta_data.MaxMasteringLuminance =
|
|
(UINT)(max_output_nits * 10000.0f);
|
|
hdr10_meta_data.MinMasteringLuminance =
|
|
(UINT)(min_output_nits * 10000.0f);
|
|
hdr10_meta_data.MaxContentLightLevel =
|
|
(UINT16)(max_cll);
|
|
hdr10_meta_data.MaxFrameAverageLightLevel =
|
|
(UINT16)(max_fall);
|
|
|
|
if(g_hdr10_meta_data.RedPrimary != hdr10_meta_data.RedPrimary ||
|
|
g_hdr10_meta_data.GreenPrimary != hdr10_meta_data.GreenPrimary ||
|
|
g_hdr10_meta_data.BluePrimary != hdr10_meta_data.BluePrimary ||
|
|
g_hdr10_meta_data.WhitePoint != hdr10_meta_data.WhitePoint ||
|
|
g_hdr10_meta_data.MaxContentLightLevel != hdr10_meta_data.MaxContentLightLevel ||
|
|
g_hdr10_meta_data.MaxMasteringLuminance != hdr10_meta_data.MaxMasteringLuminance ||
|
|
g_hdr10_meta_data.MinMasteringLuminance != hdr10_meta_data.MinMasteringLuminance ||
|
|
g_hdr10_meta_data.MaxFrameAverageLightLevel != hdr10_meta_data.MaxFrameAverageLightLevel)
|
|
{
|
|
#ifdef __cplusplus
|
|
if (FAILED(handle->SetHDRMetaData(
|
|
DXGI_HDR_METADATA_TYPE_HDR10, sizeof(DXGI_HDR_METADATA_HDR10), &hdr10_meta_data)))
|
|
#else
|
|
if (FAILED(handle->lpVtbl->SetHDRMetaData(handle,
|
|
DXGI_HDR_METADATA_TYPE_HDR10, sizeof(DXGI_HDR_METADATA_HDR10), &hdr10_meta_data)))
|
|
#endif
|
|
{
|
|
RARCH_ERR("[DXGI]: Failed to set HDR meta data for HDR10\n");
|
|
return;
|
|
}
|
|
g_hdr10_meta_data = hdr10_meta_data;
|
|
}
|
|
}
|
|
#endif
|