1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-18 22:54:15 +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(
REFGUID InterfaceName,
LARGE_INTEGER *pUMDVersion) {
REFGUID InterfaceName,
LARGE_INTEGER* pUMDVersion) {
Logger::err("DxgiAdapter::CheckInterfaceSupport: No D3D10 support");
return DXGI_ERROR_UNSUPPORTED;
}
HRESULT STDMETHODCALLTYPE DxgiAdapter::EnumOutputs(
UINT Output,
IDXGIOutput **ppOutput) {
UINT Output,
IDXGIOutput** ppOutput) {
InitReturnPtr(ppOutput);
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 (mode != DxgiFormatMode::Depth) {
auto color = m_colorFormats.find(format);
@ -194,8 +196,8 @@ namespace dxvk {
HRESULT DxgiAdapter::GetOutputFromMonitor(
HMONITOR Monitor,
IDXGIOutput** ppOutput) {
HMONITOR Monitor,
IDXGIOutput** ppOutput) {
if (ppOutput == nullptr)
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(
DXGI_FORMAT srcFormat,
VkFormat dstFormat) {

View File

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

View File

@ -17,7 +17,21 @@ namespace dxvk {
HMONITOR monitor)
: m_adapter(adapter),
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");
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS *pStats) {
Logger::err("DxgiOutput::GetFrameStatistics: Not implemented");
return E_NOTIMPL;
HRESULT STDMETHODCALLTYPE DxgiOutput::GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) {
DXGI_VK_OUTPUT_DATA outputData;
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) {
Logger::err("DxgiOutput::GetGammaControl: Not implemented");
return E_NOTIMPL;
HRESULT STDMETHODCALLTYPE DxgiOutput::GetGammaControl(DXGI_GAMMA_CONTROL* pArray) {
DXGI_VK_OUTPUT_DATA outputData;
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->MaxConvertedValue = 1.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");
return E_NOTIMPL;
}
HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL *pArray) {
Logger::err("DxgiOutput::SetGammaControl: Not implemented");
return E_NOTIMPL;
HRESULT STDMETHODCALLTYPE DxgiOutput::SetGammaControl(const DXGI_GAMMA_CONTROL* pArray) {
DXGI_VK_OUTPUT_DATA outputData;
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
#include <mutex>
#include "dxgi_object.h"
namespace dxvk {
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> {

View File

@ -10,7 +10,8 @@ namespace dxvk {
IUnknown* pDevice,
DXGI_SWAP_CHAIN_DESC* pDesc)
: m_factory (factory),
m_desc (*pDesc) {
m_desc (*pDesc),
m_monitor (nullptr) {
// Retrieve a device pointer that allows us to
// communicate with the underlying D3D device
@ -177,6 +178,17 @@ namespace dxvk {
return S_OK;
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
// before recording the present code.
m_presentDevice->FlushRenderingCommands();
@ -425,12 +437,15 @@ namespace dxvk {
::SetWindowPos(m_desc.OutputWindow, HWND_TOPMOST,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
SWP_FRAMECHANGED | SWP_SHOWWINDOW | SWP_NOACTIVATE);
m_monitor = desc.Monitor;
return S_OK;
}
HRESULT DxgiSwapChain::LeaveFullscreenMode() {
m_desc.Windowed = TRUE;
m_monitor = nullptr;
// FIXME wine only restores window flags if the application
// 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,
SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE);
return S_OK;
return SetDefaultGammaControl();
}

View File

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

View File

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