mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-22 13:33:40 +00:00
[host] d12: implement hdr16 to hdr10 conversion
This commit is contained in:
parent
0184ddeedd
commit
ad7ac6540f
32
common/include/common/display.h
Normal file
32
common/include/common/display.h
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2024 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef _H_COMMON_DISPLAY_
|
||||
#define _H_COMMON_DISPLAY_
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool display_getPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info);
|
||||
float display_getSDRWhiteLevel(const DISPLAYCONFIG_PATH_INFO * displayPathInfo);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -39,6 +39,7 @@ add_library(lg_common_platform_code STATIC
|
||||
ivshmem.c
|
||||
time.c
|
||||
cpuinfo.c
|
||||
display.c
|
||||
)
|
||||
|
||||
target_link_libraries(lg_common_platform_code
|
||||
|
120
common/src/platform/windows/display.c
Normal file
120
common/src/platform/windows/display.c
Normal file
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2024 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program 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 Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "common/display.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
bool display_getPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info)
|
||||
{
|
||||
bool result = false;
|
||||
UINT32 numPath, numMode;
|
||||
|
||||
MONITORINFOEXW viewInfo = { .cbSize = sizeof(viewInfo) };
|
||||
if (!GetMonitorInfoW(monitor, (MONITORINFO*)&viewInfo))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the monitor info");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err_retry:
|
||||
if (FAILED(GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, &numMode)))
|
||||
goto err;
|
||||
|
||||
DISPLAYCONFIG_PATH_INFO * pathInfo = calloc(sizeof(*pathInfo), numPath);
|
||||
if (!pathInfo)
|
||||
goto err_mem_pathInfo;
|
||||
|
||||
DISPLAYCONFIG_MODE_INFO * modeInfo = calloc(sizeof(*modeInfo), numMode);
|
||||
if (!modeInfo)
|
||||
goto err_mem_modeInfo;
|
||||
|
||||
LONG status = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS,
|
||||
&numPath, pathInfo,
|
||||
&numMode, modeInfo,
|
||||
NULL);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
if (status == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
free(modeInfo);
|
||||
free(pathInfo);
|
||||
goto err_retry;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("QueryDisplayConfig failed with 0x%lx", status);
|
||||
goto err_queryDisplay;
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < numPath; ++i)
|
||||
{
|
||||
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME,
|
||||
.size = sizeof(sourceName),
|
||||
.adapterId = pathInfo[i].sourceInfo.adapterId,
|
||||
.id = pathInfo[i].sourceInfo.id,
|
||||
}
|
||||
};
|
||||
|
||||
if (FAILED(DisplayConfigGetDeviceInfo(&sourceName.header)))
|
||||
continue;
|
||||
|
||||
if (wcscmp(viewInfo.szDevice, sourceName.viewGdiDeviceName) != 0)
|
||||
continue;
|
||||
|
||||
*info = pathInfo[i];
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
err_queryDisplay:
|
||||
free(modeInfo);
|
||||
|
||||
err_mem_modeInfo:
|
||||
free(pathInfo);
|
||||
|
||||
err_mem_pathInfo:
|
||||
|
||||
err:
|
||||
return result;
|
||||
}
|
||||
|
||||
float display_getSDRWhiteLevel(const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
||||
{
|
||||
float nits = 80.0f;
|
||||
DISPLAYCONFIG_SDR_WHITE_LEVEL level =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL,
|
||||
.size = sizeof(level),
|
||||
.adapterId = displayPathInfo->targetInfo.adapterId,
|
||||
.id = displayPathInfo->targetInfo.id,
|
||||
}
|
||||
};
|
||||
|
||||
if (SUCCEEDED(DisplayConfigGetDeviceInfo(&level.header)))
|
||||
nits = level.SDRWhiteLevel / 1000.0f * 80.0f;
|
||||
|
||||
return nits;
|
||||
}
|
@ -6,6 +6,7 @@ add_library(capture_D12 STATIC
|
||||
command_group.c
|
||||
backend/dd.c
|
||||
effect/rgb24.c
|
||||
effect/hdr16to10.c
|
||||
)
|
||||
|
||||
target_link_libraries(capture_D12
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "common/option.h"
|
||||
#include "common/rects.h"
|
||||
#include "common/vector.h"
|
||||
#include "common/display.h"
|
||||
#include "com_ref.h"
|
||||
|
||||
#include "backend.h"
|
||||
@ -36,6 +37,7 @@
|
||||
|
||||
#include <dxgi.h>
|
||||
#include <dxgi1_3.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <d3dcommon.h>
|
||||
|
||||
// definitions
|
||||
@ -46,6 +48,8 @@ struct D12Interface
|
||||
IDXGIFactory2 ** factory;
|
||||
ID3D12Device3 ** device;
|
||||
|
||||
DISPLAYCONFIG_PATH_INFO displayPathInfo;
|
||||
|
||||
ID3D12CommandQueue ** copyQueue;
|
||||
ID3D12CommandQueue ** computeQueue;
|
||||
D12CommandGroup copyCommand;
|
||||
@ -76,6 +80,7 @@ struct D12Interface
|
||||
bool debug;
|
||||
bool trackDamage;
|
||||
bool allowRGB24;
|
||||
bool hdr16to10;
|
||||
|
||||
unsigned frameBufferCount;
|
||||
// must be last
|
||||
@ -154,6 +159,14 @@ static void d12_initOptions(void)
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = false
|
||||
},
|
||||
{
|
||||
.module = "d12",
|
||||
.name = "HDR16to10",
|
||||
.description =
|
||||
"Convert HDR16/8bpp to HDR10/4bpp (saves bandwidth)",
|
||||
.type = OPTION_TYPE_BOOL,
|
||||
.value.x_bool = true
|
||||
},
|
||||
{
|
||||
.module = "d12",
|
||||
.name = "debug",
|
||||
@ -180,9 +193,10 @@ static bool d12_create(
|
||||
return false;
|
||||
}
|
||||
|
||||
this->debug = option_get_bool("d12", "debug" );
|
||||
this->trackDamage = option_get_bool("d12", "trackDamage");
|
||||
this->allowRGB24 = option_get_bool("d12", "allowRGB24" );
|
||||
this->debug = option_get_bool("d12", "debug" );
|
||||
this->trackDamage = option_get_bool("d12", "trackDamage" );
|
||||
this->allowRGB24 = option_get_bool("d12", "allowRGB24" );
|
||||
this->hdr16to10 = option_get_bool("d12", "HDR16to10" );
|
||||
|
||||
DEBUG_INFO(
|
||||
"debug:%d trackDamage:%d allowRGB24:%d",
|
||||
@ -264,6 +278,23 @@ static bool d12_init(void * ivshmemBase, unsigned * alignSize)
|
||||
ID3D12Debug1_SetEnableSynchronizedCommandQueueValidation(*debug, TRUE);
|
||||
}
|
||||
|
||||
// get the display path info
|
||||
comRef_defineLocal(IDXGIOutput6, output6);
|
||||
hr = IDXGIOutput_QueryInterface(*output, &IID_IDXGIOutput6, (void **)output6);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to obtain the IDXGIOutput6 interface", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
||||
if (!display_getPathInfo(desc1.Monitor, &this->displayPathInfo))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the display path info");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// create the D3D12 device
|
||||
comRef_defineLocal(ID3D12Device3, device);
|
||||
hr = DX12.D3D12CreateDevice(
|
||||
@ -353,13 +384,22 @@ retryCreateCommandQueue:
|
||||
|
||||
// create the vector of effects
|
||||
vector_create(&this->effects, sizeof(D12Effect *), 0);
|
||||
D12Effect * effect;
|
||||
|
||||
if (this->hdr16to10)
|
||||
{
|
||||
if (!d12_effectCreate(&D12Effect_HDR16to10, &effect, *device,
|
||||
&this->displayPathInfo))
|
||||
goto exit;
|
||||
vector_push(&this->effects, &effect);
|
||||
}
|
||||
|
||||
/* if RGB24 conversion is enabled add the effect to the list
|
||||
NOTE: THIS MUST BE THE LAST EFFECT */
|
||||
if (this->allowRGB24)
|
||||
{
|
||||
D12Effect * effect;
|
||||
if (!d12_effectCreate(&D12Effect_RGB24, &effect, *device))
|
||||
if (!d12_effectCreate(&D12Effect_RGB24, &effect, *device,
|
||||
&this->displayPathInfo))
|
||||
goto exit;
|
||||
vector_push(&this->effects, &effect);
|
||||
}
|
||||
@ -494,12 +534,14 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
|
||||
this->captureFormat = srcFormat;
|
||||
|
||||
D12Effect * effect;
|
||||
D12FrameFormat curFormat = srcFormat;
|
||||
vector_forEach(effect, &this->effects)
|
||||
{
|
||||
dstFormat = srcFormat;
|
||||
switch(d12_effectSetFormat(effect, *this->device, &srcFormat, &dstFormat))
|
||||
dstFormat = curFormat;
|
||||
switch(d12_effectSetFormat(effect, *this->device, &curFormat, &dstFormat))
|
||||
{
|
||||
case D12_EFFECT_STATUS_OK:
|
||||
curFormat = dstFormat;
|
||||
effect->enabled = true;
|
||||
break;
|
||||
|
||||
@ -542,8 +584,8 @@ static CaptureResult d12_waitFrame(unsigned frameBufferIndex,
|
||||
const unsigned int maxRows = maxFrameSize / layout.Footprint.RowPitch;
|
||||
|
||||
frame->formatVer = this->formatVer;
|
||||
frame->screenWidth = srcFormat.desc.Width;
|
||||
frame->screenHeight = srcFormat.desc.Height;
|
||||
frame->screenWidth = srcFormat.width;
|
||||
frame->screenHeight = srcFormat.height;
|
||||
frame->dataWidth = dstFormat.desc.Width;
|
||||
frame->dataHeight = min(maxRows, dstFormat.desc.Height);
|
||||
frame->frameWidth = dstFormat.width;
|
||||
|
@ -42,7 +42,8 @@ struct D12Effect
|
||||
|
||||
bool enabled;
|
||||
|
||||
bool (*create)(D12Effect ** instance, ID3D12Device3 * device);
|
||||
bool (*create)(D12Effect ** instance, ID3D12Device3 * device,
|
||||
const DISPLAYCONFIG_PATH_INFO * displayPathInfo);
|
||||
|
||||
void (*free)(D12Effect ** instance);
|
||||
|
||||
@ -61,9 +62,10 @@ struct D12Effect
|
||||
};
|
||||
|
||||
static inline bool d12_effectCreate(const D12Effect * effect,
|
||||
D12Effect ** instance, ID3D12Device3 * device)
|
||||
D12Effect ** instance, ID3D12Device3 * device,
|
||||
const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
||||
{
|
||||
if (!effect->create(instance, device))
|
||||
if (!effect->create(instance, device, displayPathInfo))
|
||||
return false;
|
||||
memcpy(*instance, effect, sizeof(*effect));
|
||||
return true;
|
||||
@ -94,5 +96,6 @@ static inline ID3D12Resource * d12_effectRun(D12Effect * effect,
|
||||
// effect defines
|
||||
|
||||
extern const D12Effect D12Effect_RGB24;
|
||||
extern const D12Effect D12Effect_HDR16to10;
|
||||
|
||||
#endif
|
||||
|
454
host/platform/Windows/capture/D12/effect/hdr16to10.c
Normal file
454
host/platform/Windows/capture/D12/effect/hdr16to10.c
Normal file
@ -0,0 +1,454 @@
|
||||
#include "effect.h"
|
||||
|
||||
#include "d12.h"
|
||||
#include "command_group.h"
|
||||
|
||||
#include "com_ref.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/windebug.h"
|
||||
#include "common/array.h"
|
||||
#include "common/display.h"
|
||||
|
||||
#include <d3dcompiler.h>
|
||||
|
||||
typedef struct HDR16to10Inst
|
||||
{
|
||||
D12Effect base;
|
||||
|
||||
const DISPLAYCONFIG_PATH_INFO * displayPathInfo;
|
||||
struct
|
||||
{
|
||||
float SDRWhiteLevel;
|
||||
}
|
||||
consts;
|
||||
|
||||
ID3D12RootSignature ** rootSignature;
|
||||
ID3D12PipelineState ** pso;
|
||||
ID3D12DescriptorHeap ** descHeap;
|
||||
ID3D12Resource ** constBuffer;
|
||||
|
||||
unsigned threadsX, threadsY;
|
||||
ID3D12Resource ** dst;
|
||||
}
|
||||
HDR16to10Inst;
|
||||
|
||||
#define THREADS 8
|
||||
|
||||
static bool d12_effect_hdr16to10Create(D12Effect ** instance,
|
||||
ID3D12Device3 * device, const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
||||
{
|
||||
HDR16to10Inst * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
{
|
||||
DEBUG_ERROR("out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
HRESULT hr;
|
||||
comRef_scopePush(10);
|
||||
|
||||
this->displayPathInfo = displayPathInfo;
|
||||
|
||||
// shader resource view
|
||||
D3D12_DESCRIPTOR_RANGE descriptorRanges[3] =
|
||||
{
|
||||
{
|
||||
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
|
||||
.NumDescriptors = 1,
|
||||
.BaseShaderRegister = 0,
|
||||
.RegisterSpace = 0,
|
||||
.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
|
||||
},
|
||||
{
|
||||
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
|
||||
.NumDescriptors = 1,
|
||||
.BaseShaderRegister = 0,
|
||||
.RegisterSpace = 0,
|
||||
.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
|
||||
},
|
||||
{
|
||||
.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
|
||||
.NumDescriptors = 1,
|
||||
.BaseShaderRegister = 0,
|
||||
.RegisterSpace = 0,
|
||||
.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND
|
||||
}
|
||||
};
|
||||
|
||||
// descriptor table
|
||||
D3D12_ROOT_PARAMETER rootParams[1] =
|
||||
{
|
||||
{
|
||||
.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||
.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL,
|
||||
.DescriptorTable =
|
||||
{
|
||||
.NumDescriptorRanges = ARRAY_LENGTH(descriptorRanges),
|
||||
.pDescriptorRanges = descriptorRanges
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// root signature
|
||||
D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc =
|
||||
{
|
||||
.Version = D3D_ROOT_SIGNATURE_VERSION_1,
|
||||
.Desc_1_0 =
|
||||
{
|
||||
.NumParameters = ARRAY_LENGTH(rootParams),
|
||||
.pParameters = rootParams,
|
||||
.NumStaticSamplers = 0,
|
||||
.pStaticSamplers = NULL,
|
||||
.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE
|
||||
}
|
||||
};
|
||||
|
||||
// Serialize the root signature
|
||||
comRef_defineLocal(ID3DBlob, blob );
|
||||
comRef_defineLocal(ID3DBlob, error);
|
||||
hr = DX12.D3D12SerializeVersionedRootSignature(
|
||||
&rootSignatureDesc, blob, error);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to serialize the root signature", hr);
|
||||
DEBUG_ERROR("%s", (const char *)ID3DBlob_GetBufferPointer(*error));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Create the root signature
|
||||
comRef_defineLocal(ID3D12RootSignature, rootSignature);
|
||||
hr = ID3D12Device_CreateRootSignature(
|
||||
device,
|
||||
0,
|
||||
ID3DBlob_GetBufferPointer(*blob),
|
||||
ID3DBlob_GetBufferSize(*blob),
|
||||
&IID_ID3D12RootSignature,
|
||||
(void **)rootSignature);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the root signature", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Compile the shader
|
||||
const char * testCode =
|
||||
"cbuffer Constants : register(b0)\n"
|
||||
"{\n"
|
||||
" float SDRWhiteLevel;\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"Texture2D <float4> src : register(t0);\n"
|
||||
"RWTexture2D<float4> dst : register(u0);\n"
|
||||
"\n"
|
||||
"[numthreads(" STR(THREADS) ", " STR(THREADS) ", 1)]\n"
|
||||
"void main(uint3 dt : SV_DispatchThreadID)\n"
|
||||
"{\n"
|
||||
" dst[dt.xy] = src[dt.xy] * SDRWhiteLevel;"
|
||||
"}\n";
|
||||
|
||||
bool debug = false;
|
||||
hr = D3DCompile(
|
||||
testCode, strlen(testCode),
|
||||
NULL, NULL, NULL, "main", "cs_5_0",
|
||||
debug ? (D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION) : 0,
|
||||
0, blob, error);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR("Failed to compile the shader");
|
||||
DEBUG_ERROR("%s", (const char *)ID3DBlob_GetBufferPointer(*error));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Create the PSO
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc =
|
||||
{
|
||||
.pRootSignature = *rootSignature,
|
||||
.CS =
|
||||
{
|
||||
.pShaderBytecode = ID3DBlob_GetBufferPointer(*blob),
|
||||
.BytecodeLength = ID3DBlob_GetBufferSize (*blob)
|
||||
}
|
||||
};
|
||||
|
||||
comRef_defineLocal(ID3D12PipelineState, pso);
|
||||
hr = ID3D12Device3_CreateComputePipelineState(
|
||||
device, &psoDesc, &IID_ID3D12PipelineState, (void **)pso);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the PSO", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Create the descriptor heap
|
||||
D3D12_DESCRIPTOR_HEAP_DESC descHeapDesc =
|
||||
{
|
||||
.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||
.NumDescriptors = ARRAY_LENGTH(descriptorRanges),
|
||||
.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
|
||||
.NodeMask = 0
|
||||
};
|
||||
|
||||
comRef_defineLocal(ID3D12DescriptorHeap, descHeap);
|
||||
hr = ID3D12Device3_CreateDescriptorHeap(
|
||||
device, &descHeapDesc, &IID_ID3D12DescriptorHeap, (void **)descHeap);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the parameter heap", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
D3D12_HEAP_PROPERTIES constHeapProps =
|
||||
{
|
||||
.Type = D3D12_HEAP_TYPE_UPLOAD,
|
||||
.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN
|
||||
};
|
||||
|
||||
D3D12_RESOURCE_DESC constBufferDesc =
|
||||
{
|
||||
.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER,
|
||||
.Width = ALIGN_TO(sizeof(this->consts),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT),
|
||||
.Height = 1,
|
||||
.DepthOrArraySize = 1,
|
||||
.MipLevels = 1,
|
||||
.Format = DXGI_FORMAT_UNKNOWN,
|
||||
.SampleDesc.Count = 1,
|
||||
.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||
.Flags = D3D12_RESOURCE_FLAG_NONE
|
||||
};
|
||||
|
||||
comRef_defineLocal(ID3D12Resource, constBuffer);
|
||||
hr = ID3D12Device3_CreateCommittedResource(
|
||||
device,
|
||||
&constHeapProps,
|
||||
D3D12_HEAP_FLAG_NONE,
|
||||
&constBufferDesc,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
NULL,
|
||||
&IID_ID3D12Resource,
|
||||
(void **)constBuffer);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_WINERROR("Failed to create the constant buffer resource", hr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
comRef_toGlobal(this->rootSignature, rootSignature);
|
||||
comRef_toGlobal(this->pso , pso );
|
||||
comRef_toGlobal(this->descHeap , descHeap );
|
||||
comRef_toGlobal(this->constBuffer , constBuffer );
|
||||
|
||||
result = true;
|
||||
|
||||
exit:
|
||||
if (result)
|
||||
*instance = &this->base;
|
||||
else
|
||||
free(this);
|
||||
|
||||
comRef_scopePop();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void d12_effect_hdr16to10Free(D12Effect ** instance)
|
||||
{
|
||||
HDR16to10Inst * this = UPCAST(HDR16to10Inst, *instance);
|
||||
|
||||
free(this);
|
||||
}
|
||||
|
||||
static D12EffectStatus d12_effect_hdr16to10SetFormat(D12Effect * effect,
|
||||
ID3D12Device3 * device,
|
||||
const D12FrameFormat * src,
|
||||
D12FrameFormat * dst)
|
||||
{
|
||||
HDR16to10Inst * this = UPCAST(HDR16to10Inst, effect);
|
||||
comRef_scopePush(1);
|
||||
|
||||
D12EffectStatus result = D12_EFFECT_STATUS_ERROR;
|
||||
HRESULT hr;
|
||||
|
||||
if (src->desc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT ||
|
||||
src->colorSpace != DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
|
||||
{
|
||||
result = D12_EFFECT_STATUS_BYPASS;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps =
|
||||
{
|
||||
.Type = D3D12_HEAP_TYPE_DEFAULT,
|
||||
.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN,
|
||||
.CreationNodeMask = 1,
|
||||
.VisibleNodeMask = 1
|
||||
};
|
||||
|
||||
D3D12_RESOURCE_DESC desc =
|
||||
{
|
||||
.Format = DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
.Width = src->desc.Width,
|
||||
.Height = src->desc.Height,
|
||||
.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D,
|
||||
.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
|
||||
.MipLevels = 1,
|
||||
.DepthOrArraySize = 1,
|
||||
.SampleDesc.Count = 1
|
||||
};
|
||||
|
||||
comRef_defineLocal(ID3D12Resource, res);
|
||||
hr = ID3D12Device3_CreateCommittedResource(
|
||||
device, &heapProps, D3D12_HEAP_FLAG_CREATE_NOT_ZEROED, &desc,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE, NULL, &IID_ID3D12Resource,
|
||||
(void **)res);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR("Failed to create the destination texture");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
comRef_toGlobal(this->dst, res);
|
||||
this->threadsX = (desc.Width + (THREADS-1)) / THREADS;
|
||||
this->threadsY = (desc.Height + (THREADS-1)) / THREADS;
|
||||
|
||||
dst->desc = desc;
|
||||
dst->format = CAPTURE_FMT_RGBA10;
|
||||
result = D12_EFFECT_STATUS_OK;
|
||||
|
||||
exit:
|
||||
comRef_scopePop();
|
||||
return result;
|
||||
}
|
||||
|
||||
static ID3D12Resource * d12_effect_hdr16to10Run(D12Effect * effect,
|
||||
ID3D12Device3 * device, ID3D12GraphicsCommandList * commandList,
|
||||
ID3D12Resource * src, RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||
{
|
||||
HDR16to10Inst * this = UPCAST(HDR16to10Inst, effect);
|
||||
|
||||
float nits = 80.0f / display_getSDRWhiteLevel(this->displayPathInfo);
|
||||
if (nits != this->consts.SDRWhiteLevel)
|
||||
{
|
||||
this->consts.SDRWhiteLevel = nits;
|
||||
|
||||
void * data;
|
||||
D3D12_RANGE readRange = { 0, 0 };
|
||||
HRESULT hr = ID3D12Resource_Map(*this->constBuffer, 0, &readRange, &data);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
memcpy(data, &this->consts, sizeof(this->consts));
|
||||
ID3D12Resource_Unmap(*this->constBuffer, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// transition the destination texture to unordered access so we can write to it
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier =
|
||||
{
|
||||
.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
.Transition =
|
||||
{
|
||||
.pResource = *this->dst,
|
||||
.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
.StateAfter = D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES
|
||||
}
|
||||
};
|
||||
ID3D12GraphicsCommandList_ResourceBarrier(commandList, 1, &barrier);
|
||||
}
|
||||
|
||||
// get the heap handle
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE cpuSrvUavHandle =
|
||||
ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(*this->descHeap);
|
||||
|
||||
// descriptor for input CBV
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc =
|
||||
{
|
||||
.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(*this->constBuffer),
|
||||
.SizeInBytes = ALIGN_TO(sizeof(this->consts),
|
||||
D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT)
|
||||
};
|
||||
ID3D12Device3_CreateConstantBufferView(device, &cbvDesc, cpuSrvUavHandle);
|
||||
|
||||
// move to the next slot
|
||||
cpuSrvUavHandle.ptr += ID3D12Device3_GetDescriptorHandleIncrementSize(
|
||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
|
||||
// descriptor for input SRV
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc =
|
||||
{
|
||||
.Format = DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D,
|
||||
.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
|
||||
.Texture2D.MipLevels = 1
|
||||
};
|
||||
ID3D12Device3_CreateShaderResourceView(device, src, &srvDesc, cpuSrvUavHandle);
|
||||
|
||||
// move to the next slot
|
||||
cpuSrvUavHandle.ptr += ID3D12Device3_GetDescriptorHandleIncrementSize(
|
||||
device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
|
||||
// descriptor for the output UAV
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc =
|
||||
{
|
||||
.Format = DXGI_FORMAT_R10G10B10A2_UNORM,
|
||||
.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D
|
||||
};
|
||||
ID3D12Device3_CreateUnorderedAccessView(
|
||||
device, *this->dst, NULL, &uavDesc, cpuSrvUavHandle);
|
||||
|
||||
// bind the descriptor heap to the pipeline
|
||||
ID3D12GraphicsCommandList_SetDescriptorHeaps(commandList, 1, this->descHeap);
|
||||
|
||||
// set the pipeline state
|
||||
ID3D12GraphicsCommandList_SetPipelineState(commandList, *this->pso);
|
||||
|
||||
// set the root signature on the command list
|
||||
ID3D12GraphicsCommandList_SetComputeRootSignature(
|
||||
commandList, *this->rootSignature);
|
||||
|
||||
// get the GPU side handle for our heap
|
||||
D3D12_GPU_DESCRIPTOR_HANDLE gpuSrvUavHandle =
|
||||
ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(*this->descHeap);
|
||||
|
||||
// bind the descriptor tables to the root signature
|
||||
ID3D12GraphicsCommandList_SetComputeRootDescriptorTable(
|
||||
commandList, 0, gpuSrvUavHandle);
|
||||
|
||||
ID3D12GraphicsCommandList_Dispatch(
|
||||
commandList, this->threadsX, this->threadsY, 1);
|
||||
|
||||
// transition the destination texture to a copy source for the next stage
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier =
|
||||
{
|
||||
.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION,
|
||||
.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE,
|
||||
.Transition =
|
||||
{
|
||||
.pResource = *this->dst,
|
||||
.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES
|
||||
}
|
||||
};
|
||||
ID3D12GraphicsCommandList_ResourceBarrier(commandList, 1, &barrier);
|
||||
}
|
||||
|
||||
// return the output buffer
|
||||
return *this->dst;
|
||||
}
|
||||
|
||||
const D12Effect D12Effect_HDR16to10 =
|
||||
{
|
||||
.name = "HDR16to10",
|
||||
.create = d12_effect_hdr16to10Create,
|
||||
.free = d12_effect_hdr16to10Free,
|
||||
.setFormat = d12_effect_hdr16to10SetFormat,
|
||||
.run = d12_effect_hdr16to10Run
|
||||
};
|
@ -25,7 +25,8 @@ TestInstance;
|
||||
|
||||
#define THREADS 8
|
||||
|
||||
static bool d12_effect_rgb24Create(D12Effect ** instance, ID3D12Device3 * device)
|
||||
static bool d12_effect_rgb24Create(D12Effect ** instance, ID3D12Device3 * device,
|
||||
const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
||||
{
|
||||
TestInstance * this = calloc(1, sizeof(*this));
|
||||
if (!this)
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/windebug.h"
|
||||
#include "common/display.h"
|
||||
|
||||
#include <dxgi1_6.h>
|
||||
|
||||
@ -92,7 +93,7 @@ static bool sdrWhiteLevel_setup(
|
||||
|
||||
DXGI_OUTPUT_DESC1 desc1;
|
||||
IDXGIOutput6_GetDesc1(*output6, &desc1);
|
||||
if (!getDisplayPathInfo(desc1.Monitor, &this.displayPathInfo))
|
||||
if (!display_getPathInfo(desc1.Monitor, &this.displayPathInfo))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the display path info");
|
||||
goto exit;
|
||||
@ -214,7 +215,7 @@ static void sdrWhiteLevel_free(void * opaque)
|
||||
|
||||
static void updateConsts(void)
|
||||
{
|
||||
float nits = getSDRWhiteLevel(&this.displayPathInfo);
|
||||
float nits = display_getSDRWhiteLevel(&this.displayPathInfo);
|
||||
if (nits == this.sdrWhiteLevel)
|
||||
return;
|
||||
|
||||
|
@ -224,104 +224,6 @@ bool compileShader(ID3DBlob ** dst, const char * entry, const char * target,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getDisplayPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info)
|
||||
{
|
||||
bool result = false;
|
||||
UINT32 numPath, numMode;
|
||||
|
||||
MONITORINFOEXW viewInfo = { .cbSize = sizeof(viewInfo) };
|
||||
if (!GetMonitorInfoW(monitor, (MONITORINFO*)&viewInfo))
|
||||
{
|
||||
DEBUG_ERROR("Failed to get the monitor info");
|
||||
goto err;
|
||||
}
|
||||
|
||||
err_retry:
|
||||
if (FAILED(GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, &numMode)))
|
||||
goto err;
|
||||
|
||||
DISPLAYCONFIG_PATH_INFO * pathInfo = calloc(sizeof(*pathInfo), numPath);
|
||||
if (!pathInfo)
|
||||
goto err_mem_pathInfo;
|
||||
|
||||
DISPLAYCONFIG_MODE_INFO * modeInfo = calloc(sizeof(*modeInfo), numMode);
|
||||
if (!modeInfo)
|
||||
goto err_mem_modeInfo;
|
||||
|
||||
LONG status = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS,
|
||||
&numPath, pathInfo,
|
||||
&numMode, modeInfo,
|
||||
NULL);
|
||||
|
||||
if (status != ERROR_SUCCESS)
|
||||
{
|
||||
if (status == ERROR_INSUFFICIENT_BUFFER)
|
||||
{
|
||||
free(modeInfo);
|
||||
free(pathInfo);
|
||||
goto err_retry;
|
||||
}
|
||||
|
||||
DEBUG_ERROR("QueryDisplayConfig failed with 0x%lx", status);
|
||||
goto err_queryDisplay;
|
||||
}
|
||||
|
||||
for(unsigned i = 0; i < numPath; ++i)
|
||||
{
|
||||
DISPLAYCONFIG_SOURCE_DEVICE_NAME sourceName =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME,
|
||||
.size = sizeof(sourceName),
|
||||
.adapterId = pathInfo[i].sourceInfo.adapterId,
|
||||
.id = pathInfo[i].sourceInfo.id,
|
||||
}
|
||||
};
|
||||
|
||||
if (FAILED(DisplayConfigGetDeviceInfo(&sourceName.header)))
|
||||
continue;
|
||||
|
||||
if (wcscmp(viewInfo.szDevice, sourceName.viewGdiDeviceName) != 0)
|
||||
continue;
|
||||
|
||||
*info = pathInfo[i];
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
err_queryDisplay:
|
||||
free(modeInfo);
|
||||
|
||||
err_mem_modeInfo:
|
||||
free(pathInfo);
|
||||
|
||||
err_mem_pathInfo:
|
||||
|
||||
err:
|
||||
return result;
|
||||
}
|
||||
|
||||
float getSDRWhiteLevel(const DISPLAYCONFIG_PATH_INFO * displayPathInfo)
|
||||
{
|
||||
float nits = 80.0f;
|
||||
DISPLAYCONFIG_SDR_WHITE_LEVEL level =
|
||||
{
|
||||
.header =
|
||||
{
|
||||
.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL,
|
||||
.size = sizeof(level),
|
||||
.adapterId = displayPathInfo->targetInfo.adapterId,
|
||||
.id = displayPathInfo->targetInfo.id,
|
||||
}
|
||||
};
|
||||
|
||||
if (SUCCEEDED(DisplayConfigGetDeviceInfo(&level.header)))
|
||||
nits = level.SDRWhiteLevel / 1000.0f * 80.0f;
|
||||
|
||||
return nits;
|
||||
}
|
||||
|
||||
DXGI_FORMAT getDXGIFormat(CaptureFormat format)
|
||||
{
|
||||
switch(format)
|
||||
|
@ -30,8 +30,4 @@ const char * getDXGIColorSpaceTypeStr(DXGI_COLOR_SPACE_TYPE type);
|
||||
bool compileShader(ID3DBlob ** dst, const char * entry, const char * target,
|
||||
const char * code, const D3D_SHADER_MACRO * defines);
|
||||
|
||||
bool getDisplayPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info);
|
||||
|
||||
float getSDRWhiteLevel(const DISPLAYCONFIG_PATH_INFO * displayPathInfo);
|
||||
|
||||
DXGI_FORMAT getDXGIFormat(CaptureFormat format);
|
||||
|
Loading…
Reference in New Issue
Block a user