1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-21 22:54:16 +01:00

[dxgi] Re-implement gamma control functions

This commit is contained in:
Philip Rebohle 2018-04-12 13:38:22 +02:00
parent 654e9e6fd8
commit f5679211cd
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 169 additions and 61 deletions

View File

@ -49,16 +49,16 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE DxgiAdapter::CheckInterfaceSupport( HRESULT STDMETHODCALLTYPE DxgiAdapter::CheckInterfaceSupport(
REFGUID InterfaceName, REFGUID InterfaceName,
LARGE_INTEGER *pUMDVersion) { LARGE_INTEGER* pUMDVersion) {
Logger::err("DxgiAdapter::CheckInterfaceSupport: No D3D10 support"); Logger::err("DxgiAdapter::CheckInterfaceSupport: No D3D10 support");
return DXGI_ERROR_UNSUPPORTED; return DXGI_ERROR_UNSUPPORTED;
} }
HRESULT STDMETHODCALLTYPE DxgiAdapter::EnumOutputs( HRESULT STDMETHODCALLTYPE DxgiAdapter::EnumOutputs(
UINT Output, UINT Output,
IDXGIOutput **ppOutput) { IDXGIOutput** ppOutput) {
InitReturnPtr(ppOutput); InitReturnPtr(ppOutput);
if (ppOutput == nullptr) if (ppOutput == nullptr)
@ -173,7 +173,9 @@ namespace dxvk {
} }
DxgiFormatInfo STDMETHODCALLTYPE DxgiAdapter::LookupFormat(DXGI_FORMAT format, DxgiFormatMode mode) { DxgiFormatInfo STDMETHODCALLTYPE DxgiAdapter::LookupFormat(
DXGI_FORMAT format,
DxgiFormatMode mode) {
// If the mode is 'Any', probe color formats first // If the mode is 'Any', probe color formats first
if (mode != DxgiFormatMode::Depth) { if (mode != DxgiFormatMode::Depth) {
auto color = m_colorFormats.find(format); auto color = m_colorFormats.find(format);
@ -194,8 +196,8 @@ namespace dxvk {
HRESULT DxgiAdapter::GetOutputFromMonitor( HRESULT DxgiAdapter::GetOutputFromMonitor(
HMONITOR Monitor, HMONITOR Monitor,
IDXGIOutput** ppOutput) { IDXGIOutput** ppOutput) {
if (ppOutput == nullptr) if (ppOutput == nullptr)
return DXGI_ERROR_INVALID_CALL; return DXGI_ERROR_INVALID_CALL;
@ -215,6 +217,33 @@ namespace dxvk {
} }
HRESULT DxgiAdapter::GetOutputData(
HMONITOR Monitor,
DXGI_VK_OUTPUT_DATA* pOutputData) {
std::lock_guard<std::mutex> lock(m_outputMutex);
auto entry = m_outputData.find(Monitor);
if (entry == m_outputData.end())
return DXGI_ERROR_NOT_FOUND;
if (pOutputData == nullptr)
return S_FALSE;
*pOutputData = entry->second;
return S_OK;
}
HRESULT DxgiAdapter::SetOutputData(
HMONITOR Monitor,
const DXGI_VK_OUTPUT_DATA* pOutputData) {
std::lock_guard<std::mutex> lock(m_outputMutex);
m_outputData.insert_or_assign(Monitor, *pOutputData);
return S_OK;
}
void DxgiAdapter::AddColorFormatTypeless( void DxgiAdapter::AddColorFormatTypeless(
DXGI_FORMAT srcFormat, DXGI_FORMAT srcFormat,
VkFormat dstFormat) { VkFormat dstFormat) {

View File

@ -9,7 +9,7 @@
#include <dxvk_adapter.h> #include <dxvk_adapter.h>
#include "dxgi_interfaces.h" #include "dxgi_interfaces.h"
#include "dxgi_object.h" #include "dxgi_output.h"
namespace dxvk { namespace dxvk {
@ -26,26 +26,26 @@ namespace dxvk {
~DxgiAdapter(); ~DxgiAdapter();
HRESULT STDMETHODCALLTYPE QueryInterface( HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid, REFIID riid,
void **ppvObject) final; void** ppvObject) final;
HRESULT STDMETHODCALLTYPE GetParent( HRESULT STDMETHODCALLTYPE GetParent(
REFIID riid, REFIID riid,
void **ppParent) final; void** ppParent) final;
HRESULT STDMETHODCALLTYPE CheckInterfaceSupport( HRESULT STDMETHODCALLTYPE CheckInterfaceSupport(
REFGUID InterfaceName, REFGUID InterfaceName,
LARGE_INTEGER *pUMDVersion) final; LARGE_INTEGER* pUMDVersion) final;
HRESULT STDMETHODCALLTYPE EnumOutputs( HRESULT STDMETHODCALLTYPE EnumOutputs(
UINT Output, UINT Output,
IDXGIOutput **ppOutput) final; IDXGIOutput** ppOutput) final;
HRESULT STDMETHODCALLTYPE GetDesc( HRESULT STDMETHODCALLTYPE GetDesc(
DXGI_ADAPTER_DESC *pDesc) final; DXGI_ADAPTER_DESC* pDesc) final;
HRESULT STDMETHODCALLTYPE GetDesc1( HRESULT STDMETHODCALLTYPE GetDesc1(
DXGI_ADAPTER_DESC1 *pDesc) final; DXGI_ADAPTER_DESC1* pDesc) final;
Rc<DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() final; Rc<DxvkAdapter> STDMETHODCALLTYPE GetDXVKAdapter() final;
@ -55,15 +55,25 @@ namespace dxvk {
IDXGIVkDevice** ppDevice) final; IDXGIVkDevice** ppDevice) final;
DxgiFormatInfo STDMETHODCALLTYPE LookupFormat( DxgiFormatInfo STDMETHODCALLTYPE LookupFormat(
DXGI_FORMAT format, DxgiFormatMode mode) final; DXGI_FORMAT format,
DxgiFormatMode mode) final;
HRESULT GetOutputFromMonitor( HRESULT GetOutputFromMonitor(
HMONITOR Monitor, HMONITOR Monitor,
IDXGIOutput** ppOutput); IDXGIOutput** ppOutput);
HRESULT GetOutputData(
HMONITOR Monitor,
DXGI_VK_OUTPUT_DATA* pOutputData);
HRESULT SetOutputData(
HMONITOR Monitor,
const DXGI_VK_OUTPUT_DATA* pOutputData);
private: private:
using FormatMap = std::unordered_map<DXGI_FORMAT, DxgiFormatInfo>; using FormatMap = std::unordered_map<DXGI_FORMAT, DxgiFormatInfo>;
using OutputMap = std::unordered_map<HMONITOR, DXGI_VK_OUTPUT_DATA>;
Com<DxgiFactory> m_factory; Com<DxgiFactory> m_factory;
Rc<DxvkAdapter> m_adapter; Rc<DxvkAdapter> m_adapter;
@ -71,6 +81,9 @@ namespace dxvk {
FormatMap m_colorFormats; FormatMap m_colorFormats;
FormatMap m_depthFormats; FormatMap m_depthFormats;
std::mutex m_outputMutex;
OutputMap m_outputData;
void AddColorFormatTypeless( void AddColorFormatTypeless(
DXGI_FORMAT srcFormat, DXGI_FORMAT srcFormat,
VkFormat dstFormat); VkFormat dstFormat);

View File

@ -17,7 +17,21 @@ namespace dxvk {
HMONITOR monitor) HMONITOR monitor)
: m_adapter(adapter), : m_adapter(adapter),
m_monitor(monitor) { m_monitor(monitor) {
// Init output data if necessary
if (FAILED(m_adapter->GetOutputData(m_monitor, nullptr))) {
DXGI_VK_OUTPUT_DATA outputData;
outputData.FrameStats = DXGI_FRAME_STATISTICS();
outputData.GammaCurve.Scale = { 1.0f, 1.0f, 1.0f };
outputData.GammaCurve.Offset = { 0.0f, 0.0f, 0.0f };
for (uint32_t i = 0; i < DxgiPresenterGammaRamp::CpCount; i++) {
const float value = DxgiPresenterGammaRamp::cpLocation(i);
outputData.GammaCurve.GammaCurve[i] = { value, value, value };
}
outputData.GammaDirty = FALSE;
m_adapter->SetOutputData(m_monitor, &outputData);
}
} }
@ -223,25 +237,39 @@ namespace dxvk {
} }
HRESULT STDMETHODCALLTYPE DxgiOutput::GetDisplaySurfaceData(IDXGISurface *pDestination) { HRESULT STDMETHODCALLTYPE DxgiOutput::GetDisplaySurfaceData(IDXGISurface* pDestination) {
Logger::err("DxgiOutput::GetDisplaySurfaceData: Not implemented"); Logger::err("DxgiOutput::GetDisplaySurfaceData: Not implemented");
return E_NOTIMPL; return E_NOTIMPL;
} }
HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) { HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) {
Logger::err("DxgiOutput::GetFrameStatistics: Not implemented"); DXGI_VK_OUTPUT_DATA outputData;
return E_NOTIMPL;
if (FAILED(m_adapter->GetOutputData(m_monitor, &outputData))) {
Logger::err("DxgiOutput: Failed to query output data");
return E_FAIL;
}
*pStats = outputData.FrameStats;
return S_OK;
} }
HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL *pArray) { HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL* pArray) {
Logger::err("DxgiOutput::GetGammaControl: Not implemented"); DXGI_VK_OUTPUT_DATA outputData;
return E_NOTIMPL;
if (FAILED(m_adapter->GetOutputData(m_monitor, &outputData))) {
Logger::err("DxgiOutput: Failed to query output data");
return E_FAIL;
}
*pArray = outputData.GammaCurve;
return S_OK;
} }
HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControlCapabilities(DXGI_GAMMA_CONTROL_CAPABILITIES *pGammaCaps) { HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControlCapabilities(DXGI_GAMMA_CONTROL_CAPABILITIES* pGammaCaps) {
pGammaCaps->ScaleAndOffsetSupported = TRUE; pGammaCaps->ScaleAndOffsetSupported = TRUE;
pGammaCaps->MaxConvertedValue = 1.0f; pGammaCaps->MaxConvertedValue = 1.0f;
pGammaCaps->MinConvertedValue = 0.0f; pGammaCaps->MinConvertedValue = 0.0f;
@ -258,15 +286,27 @@ namespace dxvk {
} }
HRESULT STDMETHODCALLTYPE DxgiOutput::SetDisplaySurface(IDXGISurface *pScanoutSurface) { HRESULT STDMETHODCALLTYPE DxgiOutput::SetDisplaySurface(IDXGISurface* pScanoutSurface) {
Logger::err("DxgiOutput::SetDisplaySurface: Not implemented"); Logger::err("DxgiOutput::SetDisplaySurface: Not implemented");
return E_NOTIMPL; return E_NOTIMPL;
} }
HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL *pArray) { HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL* pArray) {
Logger::err("DxgiOutput::SetGammaControl: Not implemented"); DXGI_VK_OUTPUT_DATA outputData;
return E_NOTIMPL;
if (FAILED(m_adapter->GetOutputData(m_monitor, &outputData))) {
Logger::err("DxgiOutput: Failed to query output data");
return E_FAIL;
}
outputData.GammaCurve = *pArray;
outputData.GammaDirty = TRUE;
if (FAILED(m_adapter->SetOutputData(m_monitor, &outputData))) {
Logger::err("DxgiOutput: Failed to query output data");
return E_FAIL;
} return S_OK;
} }

View File

@ -1,13 +1,23 @@
#pragma once #pragma once
#include <mutex>
#include "dxgi_object.h" #include "dxgi_object.h"
namespace dxvk { namespace dxvk {
class DxgiAdapter; class DxgiAdapter;
class DxgiSwapChain;
/**
* \brief Per-output data
*
* Persistent data for a single output, which
* is addressed using the \c HMONITOR handle.
*/
struct DXGI_VK_OUTPUT_DATA {
DXGI_FRAME_STATISTICS FrameStats;
DXGI_GAMMA_CONTROL GammaCurve;
BOOL GammaDirty;
};
class DxgiOutput : public DxgiObject<IDXGIOutput> { class DxgiOutput : public DxgiObject<IDXGIOutput> {

View File

@ -10,7 +10,8 @@ namespace dxvk {
IUnknown* pDevice, IUnknown* pDevice,
DXGI_SWAP_CHAIN_DESC* pDesc) DXGI_SWAP_CHAIN_DESC* pDesc)
: m_factory (factory), : m_factory (factory),
m_desc (*pDesc) { m_desc (*pDesc),
m_monitor (nullptr) {
// Retrieve a device pointer that allows us to // Retrieve a device pointer that allows us to
// communicate with the underlying D3D device // communicate with the underlying D3D device
@ -177,6 +178,17 @@ namespace dxvk {
return S_OK; return S_OK;
try { try {
// If in fullscreen mode, apply any updated gamma curve
// if it has been changed since the last present call.
DXGI_VK_OUTPUT_DATA outputData;
if (SUCCEEDED(m_adapter->GetOutputData(m_monitor, &outputData)) && outputData.GammaDirty) {
SetGammaControl(&outputData.GammaCurve);
outputData.GammaDirty = FALSE;
m_adapter->SetOutputData(m_monitor, &outputData);
}
// Submit pending rendering commands // Submit pending rendering commands
// before recording the present code. // before recording the present code.
m_presentDevice->FlushRenderingCommands(); m_presentDevice->FlushRenderingCommands();
@ -425,12 +437,15 @@ namespace dxvk {
::SetWindowPos(m_desc.OutputWindow, HWND_TOPMOST, ::SetWindowPos(m_desc.OutputWindow, HWND_TOPMOST,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE); SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
m_monitor = desc.Monitor;
return S_OK; return S_OK;
} }
HRESULT DxgiSwapChain::LeaveFullscreenMode() { HRESULT DxgiSwapChain::LeaveFullscreenMode() {
m_desc.Windowed = TRUE; m_desc.Windowed = TRUE;
m_monitor = nullptr;
// FIXME wine only restores window flags if the application // FIXME wine only restores window flags if the application
// has not modified them in the meantime. Some applications // has not modified them in the meantime. Some applications
@ -444,7 +459,7 @@ namespace dxvk {
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
return S_OK; return SetDefaultGammaControl();
} }

View File

@ -110,6 +110,7 @@ namespace dxvk {
Rc<DxgiPresenter> m_presenter; Rc<DxgiPresenter> m_presenter;
Com<IDXGIVkBackBuffer> m_backBuffer; Com<IDXGIVkBackBuffer> m_backBuffer;
HMONITOR m_monitor;
WindowState m_windowState; WindowState m_windowState;
DxgiPresenterGammaRamp m_gammaControl; DxgiPresenterGammaRamp m_gammaControl;

View File

@ -18,26 +18,26 @@ layout(location = 0) out vec4 o_color;
void main() { void main() {
o_color = texture(sampler2D(t_texture, s_sampler), i_texcoord); o_color = texture(sampler2D(t_texture, s_sampler), i_texcoord);
// vec3 cp_lookup = o_color.rgb; vec3 cp_lookup = o_color.rgb;
// cp_lookup *= u_gamma_ramp.in_factor.rgb; cp_lookup *= u_gamma_ramp.in_factor.rgb;
// cp_lookup += u_gamma_ramp.in_offset.rgb; cp_lookup += u_gamma_ramp.in_offset.rgb;
//
// cp_lookup = clamp( cp_lookup = clamp(
// cp_lookup * float(CP_COUNT - 1), cp_lookup * float(CP_COUNT - 1),
// 0.0f, float(CP_COUNT - 1)); 0.0f, float(CP_COUNT - 1));
//
// vec3 cp_fpart = fract(cp_lookup); vec3 cp_fpart = fract(cp_lookup);
// ivec3 cp_index = ivec3(cp_lookup); ivec3 cp_index = ivec3(cp_lookup);
//
// for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
// int cp_entry = cp_index[i]; int cp_entry = cp_index[i];
//
// float lo = u_gamma_ramp.cp_values[cp_entry + 0][i]; float lo = u_gamma_ramp.cp_values[cp_entry + 0][i];
// float hi = u_gamma_ramp.cp_values[cp_entry + 1][i]; float hi = u_gamma_ramp.cp_values[cp_entry + 1][i];
//
// if (cp_entry == CP_COUNT - 1) if (cp_entry == CP_COUNT - 1)
// hi = lo; hi = lo;
//
// o_color[i] = mix(lo, hi, cp_fpart[i]); o_color[i] = mix(lo, hi, cp_fpart[i]);
// } }
} }