mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-19 05:52:11 +01:00
[dxgi] Implement gamma ramp in presenter
Will be used to fake IDXGIOutput::SetGammaControl.
This commit is contained in:
parent
41132b8c13
commit
f13011f487
@ -8,8 +8,8 @@
|
||||
namespace dxvk {
|
||||
|
||||
DxgiPresenter::DxgiPresenter(
|
||||
const Rc<DxvkDevice>& device,
|
||||
HWND window)
|
||||
const Rc<DxvkDevice>& device,
|
||||
HWND window)
|
||||
: m_device (device),
|
||||
m_context (device->createContext()) {
|
||||
|
||||
@ -25,6 +25,18 @@ namespace dxvk {
|
||||
m_options.preferredPresentMode = VK_PRESENT_MODE_FIFO_KHR;
|
||||
m_options.preferredBufferSize = { 0u, 0u };
|
||||
|
||||
// Uniform buffer that stores the gamma ramp
|
||||
DxvkBufferCreateInfo gammaBufferInfo;
|
||||
gammaBufferInfo.size = sizeof(DxgiPresenterGammaRamp);
|
||||
gammaBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT
|
||||
| VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
|
||||
gammaBufferInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT
|
||||
| VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
gammaBufferInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT
|
||||
| VK_ACCESS_SHADER_READ_BIT;
|
||||
m_gammaBuffer = m_device->createBuffer(
|
||||
gammaBufferInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
// Sampler for presentation
|
||||
DxvkSamplerCreateInfo samplerInfo;
|
||||
samplerInfo.magFilter = VK_FILTER_NEAREST;
|
||||
@ -133,6 +145,9 @@ namespace dxvk {
|
||||
|
||||
|
||||
void DxgiPresenter::initBackBuffer(const Rc<DxvkImage>& image) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
VkImageSubresourceRange sr;
|
||||
sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
sr.baseMipLevel = 0;
|
||||
@ -140,9 +155,8 @@ namespace dxvk {
|
||||
sr.baseArrayLayer = 0;
|
||||
sr.layerCount = image->info().numLayers;
|
||||
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
m_context->initImage(image, sr);
|
||||
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
nullptr, nullptr);
|
||||
@ -209,6 +223,8 @@ namespace dxvk {
|
||||
m_context->bindResourceView(BindingIds::Texture, m_backBufferView, nullptr);
|
||||
m_context->draw(4, 1, 0, 0);
|
||||
|
||||
m_context->bindResourceBuffer(BindingIds::GammaUbo, DxvkBufferSlice(m_gammaBuffer));
|
||||
|
||||
if (m_hud != nullptr) {
|
||||
m_blendMode.enableBlending = VK_TRUE;
|
||||
m_context->setBlendMode(0, m_blendMode);
|
||||
@ -273,7 +289,6 @@ namespace dxvk {
|
||||
: m_backBuffer,
|
||||
viewInfo);
|
||||
|
||||
// TODO move this elsewhere
|
||||
this->initBackBuffer(m_backBuffer);
|
||||
}
|
||||
|
||||
@ -344,6 +359,20 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
void DxgiPresenter::setGammaRamp(const DxgiPresenterGammaRamp& data) {
|
||||
m_context->beginRecording(
|
||||
m_device->createCommandList());
|
||||
|
||||
m_context->updateBuffer(m_gammaBuffer,
|
||||
0, sizeof(DxgiPresenterGammaRamp),
|
||||
&data);
|
||||
|
||||
m_device->submitCommandList(
|
||||
m_context->endRecording(),
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
|
||||
Rc<DxvkShader> DxgiPresenter::createVertexShader() {
|
||||
const SpirvCodeBuffer codeBuffer(dxgi_presenter_vert);
|
||||
|
||||
@ -358,9 +387,10 @@ namespace dxvk {
|
||||
const SpirvCodeBuffer codeBuffer(dxgi_presenter_frag);
|
||||
|
||||
// Shader resource slots
|
||||
std::array<DxvkResourceSlot, 2> resourceSlots = {{
|
||||
{ BindingIds::Sampler, VK_DESCRIPTOR_TYPE_SAMPLER, VK_IMAGE_VIEW_TYPE_MAX_ENUM },
|
||||
{ BindingIds::Texture, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
|
||||
const std::array<DxvkResourceSlot, 3> resourceSlots = {{
|
||||
{ BindingIds::Sampler, VK_DESCRIPTOR_TYPE_SAMPLER, VK_IMAGE_VIEW_TYPE_MAX_ENUM },
|
||||
{ BindingIds::Texture, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, VK_IMAGE_VIEW_TYPE_2D },
|
||||
{ BindingIds::GammaUbo, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_IMAGE_VIEW_TYPE_MAX_ENUM },
|
||||
}};
|
||||
|
||||
// Create the actual shader module
|
||||
|
@ -12,6 +12,25 @@
|
||||
|
||||
namespace dxvk {
|
||||
|
||||
/**
|
||||
* \brief Gamma ramp
|
||||
*
|
||||
* Structure that can be used to set the gamma
|
||||
* ramp of a swap chain. This is the same data
|
||||
* structure that is used by the fragment shader.
|
||||
*/
|
||||
struct DxgiPresenterGammaRamp {
|
||||
constexpr static uint32_t CpCount = 1025;
|
||||
|
||||
float in_factor[4];
|
||||
float in_offset[4];
|
||||
float cp_values[4 * CpCount];
|
||||
|
||||
static float cpLocation(uint32_t cp) {
|
||||
return float(cp) / float(CpCount - 1);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DXGI presenter
|
||||
*
|
||||
@ -24,8 +43,8 @@ namespace dxvk {
|
||||
public:
|
||||
|
||||
DxgiPresenter(
|
||||
const Rc<DxvkDevice>& device,
|
||||
HWND window);
|
||||
const Rc<DxvkDevice>& device,
|
||||
HWND window);
|
||||
|
||||
~DxgiPresenter();
|
||||
|
||||
@ -80,11 +99,18 @@ namespace dxvk {
|
||||
*/
|
||||
VkPresentModeKHR pickPresentMode(VkPresentModeKHR preferred) const;
|
||||
|
||||
/**
|
||||
* \brief Sets gamma ramp
|
||||
* \param [in] data Gamma data
|
||||
*/
|
||||
void setGammaRamp(const DxgiPresenterGammaRamp& data);
|
||||
|
||||
private:
|
||||
|
||||
enum BindingIds : uint32_t {
|
||||
Sampler = 0,
|
||||
Texture = 1,
|
||||
Sampler = 0,
|
||||
Texture = 1,
|
||||
GammaUbo = 2,
|
||||
};
|
||||
|
||||
Rc<DxvkDevice> m_device;
|
||||
@ -93,6 +119,8 @@ namespace dxvk {
|
||||
Rc<DxvkSurface> m_surface;
|
||||
Rc<DxvkSwapchain> m_swapchain;
|
||||
|
||||
Rc<DxvkBuffer> m_gammaBuffer;
|
||||
|
||||
Rc<DxvkSampler> m_samplerFitting;
|
||||
Rc<DxvkSampler> m_samplerScaling;
|
||||
|
||||
|
@ -51,6 +51,9 @@ namespace dxvk {
|
||||
|
||||
if (FAILED(CreatePresenter()) || FAILED(CreateBackBuffer()))
|
||||
throw DxvkError("DxgiSwapChain: Failed to create presenter or back buffer");
|
||||
|
||||
if (FAILED(SetDefaultGammaRamp()))
|
||||
throw DxvkError("DxgiSwapChain: Failed to set up gamma ramp");
|
||||
}
|
||||
|
||||
|
||||
@ -265,6 +268,28 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
HRESULT DxgiSwapChain::SetDefaultGammaRamp() {
|
||||
std::lock_guard<std::recursive_mutex> lock(m_mutex);
|
||||
|
||||
for (uint32_t i = 0; i < 4; i++) {
|
||||
m_gammaControl.in_factor[i] = 1.0f;
|
||||
m_gammaControl.in_offset[i] = 0.0f;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < DxgiPresenterGammaRamp::CpCount; i++) {
|
||||
const float value = DxgiPresenterGammaRamp::cpLocation(i);
|
||||
|
||||
m_gammaControl.cp_values[4 * i + 0] = value;
|
||||
m_gammaControl.cp_values[4 * i + 1] = value;
|
||||
m_gammaControl.cp_values[4 * i + 2] = value;
|
||||
m_gammaControl.cp_values[4 * i + 3] = value;
|
||||
}
|
||||
|
||||
m_presenter->setGammaRamp(m_gammaControl);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT DxgiSwapChain::CreatePresenter() {
|
||||
try {
|
||||
m_presenter = new DxgiPresenter(
|
||||
|
@ -79,7 +79,9 @@ namespace dxvk {
|
||||
HRESULT STDMETHODCALLTYPE SetFullscreenState(
|
||||
BOOL Fullscreen,
|
||||
IDXGIOutput *pTarget) final;
|
||||
|
||||
|
||||
HRESULT SetDefaultGammaRamp();
|
||||
|
||||
private:
|
||||
|
||||
struct WindowState {
|
||||
@ -93,16 +95,18 @@ namespace dxvk {
|
||||
Com<DxgiFactory> m_factory;
|
||||
Com<DxgiAdapter> m_adapter;
|
||||
Com<DxgiDevice> m_device;
|
||||
Com<IDXGIVkPresenter> m_presentDevice;
|
||||
Com<IDXGIVkPresenter> m_presentDevice;
|
||||
|
||||
DXGI_SWAP_CHAIN_DESC m_desc;
|
||||
DXGI_FRAME_STATISTICS m_stats;
|
||||
|
||||
Rc<DxgiPresenter> m_presenter;
|
||||
Com<IDXGIVkBackBuffer> m_backBuffer;
|
||||
Com<IDXGIVkBackBuffer> m_backBuffer;
|
||||
|
||||
WindowState m_windowState;
|
||||
|
||||
DxgiPresenterGammaRamp m_gammaControl;
|
||||
|
||||
HRESULT CreatePresenter();
|
||||
HRESULT CreateBackBuffer();
|
||||
|
||||
|
@ -1,11 +1,43 @@
|
||||
#version 450
|
||||
|
||||
#define CP_COUNT 1025
|
||||
|
||||
layout(binding = 0) uniform sampler s_sampler;
|
||||
layout(binding = 1) uniform texture2D t_texture;
|
||||
|
||||
layout(binding = 2)
|
||||
uniform u_gamma_ramp_t {
|
||||
layout(offset = 0) vec4 in_factor;
|
||||
layout(offset = 16) vec4 in_offset;
|
||||
layout(offset = 32) vec4 cp_values[CP_COUNT + 1];
|
||||
} u_gamma_ramp;
|
||||
|
||||
layout(location = 0) in vec2 i_texcoord;
|
||||
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]);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user