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:
parent
654e9e6fd8
commit
f5679211cd
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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> {
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -110,6 +110,7 @@ namespace dxvk {
|
||||
Rc<DxgiPresenter> m_presenter;
|
||||
Com<IDXGIVkBackBuffer> m_backBuffer;
|
||||
|
||||
HMONITOR m_monitor;
|
||||
WindowState m_windowState;
|
||||
|
||||
DxgiPresenterGammaRamp m_gammaControl;
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user