[dxgi] Implement gamma ramp in presenter

Will be used to fake IDXGIOutput::SetGammaControl.
This commit is contained in:
Philip Rebohle 2018-04-10 20:44:55 +02:00
parent 41132b8c13
commit f13011f487
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
5 changed files with 134 additions and 15 deletions

View File

@ -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

View File

@ -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;

View File

@ -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(

View File

@ -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();

View File

@ -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]);
}
}