Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/d3d11/d3d11_swapchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
#include "d3d11_private.h"
#include "dxgi_interfaces.h"
#include "dxgi_object.hpp"
#include "dxgi_output.hpp"
#include "d3d11_context.hpp"
#include "dxmt_context.hpp"
#include "dxmt_hud_state.hpp"
#include "dxmt_statistics.hpp"
#include "dxmt_presenter.hpp"
#include "log/log.hpp"
#include "d3d11_resource.hpp"
#include "d3d11_device.hpp"
Expand Down Expand Up @@ -281,6 +283,8 @@ class MTLD3D11SwapChain final : public MTLDXGISubObject<IDXGISwapChain4, MTLD3D1
return DXGI_ERROR_NOT_CURRENTLY_AVAILABLE;
}

presenter->changeGammaRamp(nullptr);

return S_OK;
}

Expand Down Expand Up @@ -601,6 +605,10 @@ class MTLD3D11SwapChain final : public MTLDXGISubObject<IDXGISwapChain4, MTLD3D1
auto &cmd_queue = device_->GetDXMTDevice().queue();
auto chunk = cmd_queue.CurrentChunk();
chunk->signal_frame_latency_fence_ = cmd_queue.CurrentFrameSeq();
auto output = static_cast<MTLDXGIOutput *>(target_.ptr());
if (output) {
presenter->changeGammaRamp(output->GetGammaRamp());
}
if constexpr (EnableMetalFX) {
chunk->emitcc([
this, vsync_duration, backbuffer = backbuffer_->texture(),
Expand Down
52 changes: 42 additions & 10 deletions src/dxgi/dxgi_output.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
#include "com/com_guid.hpp"
#include "com/com_pointer.hpp"
#include "dxgi_interfaces.h"
#include "dxgi_object.hpp"
#include "dxgi_output.hpp"
#include "dxgi_options.hpp"
#include "dxmt_format.hpp"
#include "dxmt_presenter.hpp"
#include "log/log.hpp"
#include "util_string.hpp"
#include "wsi_monitor.hpp"
Expand Down Expand Up @@ -134,17 +135,28 @@ void FilterModesByDesc(std::vector<DXGI_MODE_DESC1> &Modes,
}
}

class MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
class MTLDXGIOutputImpl : public MTLDXGIOutput {
public:
MTLDXGIOutput(IMTLDXGIAdapter *adapter, HMONITOR monitor, DxgiOptions &options)
MTLDXGIOutputImpl(IMTLDXGIAdapter *adapter, HMONITOR monitor, DxgiOptions &options)
: adapter_(adapter), monitor_(monitor), options_(options) {
WMTGetDisplayDescription(monitor_ == wsi::getDefaultMonitor()
? WMTGetPrimaryDisplayId()
: WMTGetSecondaryDisplayId(),
&native_desc_);
for (uint32_t i = 0; i < DXMT_GAMMA_CP_COUNT; i++) {
gamma_ramp_.red[i] = gamma_ramp_.green[i] = gamma_ramp_.blue[i] =
float(i) / float(DXMT_GAMMA_CP_COUNT - 1);
}
gamma_ramp_.version = 0;
}

~MTLDXGIOutput() {}
~MTLDXGIOutputImpl() {}

DXMTGammaRamp *STDMETHODCALLTYPE GetGammaRamp() override {
if (gamma_ramp_.version == 0)
return nullptr;
return &gamma_ramp_;
}

HRESULT
STDMETHODCALLTYPE
Expand Down Expand Up @@ -287,22 +299,42 @@ class MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
gamma_caps->ScaleAndOffsetSupported = false;
gamma_caps->MaxConvertedValue = 1.0f;
gamma_caps->MinConvertedValue = 0.0f;
gamma_caps->NumGammaControlPoints = 1;
gamma_caps->NumGammaControlPoints = DXMT_GAMMA_CP_COUNT;
for (uint32_t i = 0; i < gamma_caps->NumGammaControlPoints; i++)
gamma_caps->ControlPointPositions[i] = float(i) / float(DXMT_GAMMA_CP_COUNT - 1);
return S_OK;
}

HRESULT
STDMETHODCALLTYPE
SetGammaControl(const DXGI_GAMMA_CONTROL *gamma_control) final {
ERR("Not implemented");
return E_NOTIMPL;
if (gamma_control == nullptr)
return E_NOTIMPL;

for (uint32_t i = 0; i < DXMT_GAMMA_CP_COUNT; i++) {
gamma_ramp_.red[i] = gamma_control->GammaCurve[i].Red;
gamma_ramp_.green[i] = gamma_control->GammaCurve[i].Green;
gamma_ramp_.blue[i] = gamma_control->GammaCurve[i].Blue;
}
gamma_ramp_.version++;
return S_OK;
}

HRESULT
STDMETHODCALLTYPE
GetGammaControl(DXGI_GAMMA_CONTROL *gamma_control) final {
ERR("Not implemented");
return E_NOTIMPL;
if (gamma_control == nullptr)
return E_NOTIMPL;

gamma_control->Scale = { 1.0f, 1.0f, 1.0f };
gamma_control->Offset = { 0.0f, 0.0f, 0.0f };
for (uint32_t i = 0; i < DXMT_GAMMA_CP_COUNT; i++) {
gamma_control->GammaCurve[i].Red = gamma_ramp_.red[i];
gamma_control->GammaCurve[i].Green = gamma_ramp_.green[i];
gamma_control->GammaCurve[i].Blue = gamma_ramp_.blue[i];
}

return S_OK;
}

HRESULT
Expand Down Expand Up @@ -609,7 +641,7 @@ class MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
};

Com<IDXGIOutput> CreateOutput(IMTLDXGIAdapter *pAadapter, HMONITOR monitor, DxgiOptions &options) {
return Com<IDXGIOutput>::transfer(new MTLDXGIOutput(pAadapter, monitor, options));
return Com<IDXGIOutput>::transfer(new MTLDXGIOutputImpl(pAadapter, monitor, options));
};

} // namespace dxmt
13 changes: 13 additions & 0 deletions src/dxgi/dxgi_output.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once
#include "dxgi_interfaces.h"
#include "dxgi_object.hpp"
#include "dxmt_presenter.hpp"

namespace dxmt {

struct MTLDXGIOutput : public MTLDXGIObject<IDXGIOutput6> {
DXMTGammaRamp gamma_ramp_;
virtual DXMTGammaRamp *STDMETHODCALLTYPE GetGammaRamp() = 0;
};

} // namespace dxmt
10 changes: 10 additions & 0 deletions src/dxmt/dxmt_command.metal
Original file line number Diff line number Diff line change
Expand Up @@ -280,15 +280,18 @@ constexpr constant uint kPresentFCIndex_BackbufferIsSRGB = 0x103;
constexpr constant uint kPresentFCIndex_HDRPQ = 0x101;
constexpr constant uint kPresentFCIndex_WithHDRMetadata = 0x102;
constexpr constant uint kPresentFCIndex_BackbufferIsMS = 0x104;
constexpr constant uint kPresentFCIndex_GammaEnabled = 0x105;

constant bool present_backbuffer_size_matched [[function_constant(kPresentFCIndex_BackbufferSizeMatched)]];
constant bool present_backbuffer_is_srgb [[function_constant(kPresentFCIndex_BackbufferIsSRGB)]];
constant bool present_hdr_pq [[function_constant(kPresentFCIndex_HDRPQ)]];
constant bool present_with_hdr_metadata [[function_constant(kPresentFCIndex_WithHDRMetadata)]];
constant bool present_backbuffer_is_ms [[function_constant(kPresentFCIndex_BackbufferIsMS)]];
constant bool present_backbuffer_is_not_ms = !present_backbuffer_is_ms;
constant bool present_gamma_enabled [[function_constant(kPresentFCIndex_GammaEnabled)]];

constexpr sampler s(coord::normalized);
constexpr sampler gamma_sampler(coord::normalized, filter::linear, address::clamp_to_edge);

struct DXMTPresentMetadata {
float edr_scale;
Expand All @@ -304,6 +307,7 @@ float3 to_srgb(float3 linear) {
present_data input [[stage_in]],
texture2d<float, access::sample> source [[texture(0), function_constant(present_backbuffer_is_not_ms)]],
texture2d_ms<float, access::read> source_ms [[texture(0), function_constant(present_backbuffer_is_ms)]],
texture2d<float, access::sample> gamma_lut [[texture(1), function_constant(present_gamma_enabled)]],
constant DXMTPresentMetadata& meta [[buffer(0)]]
) {
float4 output = float4(0);
Expand All @@ -319,6 +323,12 @@ float3 to_srgb(float3 linear) {
: source.sample(s, input.uv);
}
float3 output_rgb = output.xyz;
if (present_gamma_enabled && !present_hdr_pq && !present_with_hdr_metadata) {
output_rgb = float3(
gamma_lut.sample(gamma_sampler, float2(output_rgb.r, 0.5)).r,
gamma_lut.sample(gamma_sampler, float2(output_rgb.g, 0.5)).g,
gamma_lut.sample(gamma_sampler, float2(output_rgb.b, 0.5)).b);
}
float edr_scale = meta.edr_scale;
if (present_backbuffer_is_srgb)
output_rgb = to_srgb(output_rgb);
Expand Down
47 changes: 44 additions & 3 deletions src/dxmt/dxmt_presenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ Presenter::Presenter(WMT::Device device, WMT::MetalLayer layer, InternalCommandL
layer_props_.display_sync_enabled = false;
layer_props_.framebuffer_only = false; // how strangely setting it true results in worse performance
layer_props_.contents_scale = layer_props_.contents_scale * scale_factor;

WMTTextureInfo texture_info;
texture_info.type = WMTTextureType2D;
texture_info.pixel_format = WMTPixelFormatRGBA32Float;
texture_info.usage = WMTTextureUsageShaderRead;
texture_info.options = WMTResourceStorageModeShared;
texture_info.width = DXMT_GAMMA_CP_COUNT;
texture_info.height = 1;
texture_info.depth = 1;
texture_info.mipmap_level_count = 1;
texture_info.sample_count = 1;
texture_info.array_length = 1;
gamma_lut_texture_ = device.newTexture(texture_info);
}

bool
Expand Down Expand Up @@ -64,6 +77,29 @@ Presenter::changeHDRMetadata(const WMTHDRMetadata *metadata) {
}
}

void
Presenter::changeGammaRamp(const DXMTGammaRamp *gamma_ramp) {
if (!gamma_ramp && gamma_version_) {
gamma_version_ = 0;
pso_valid.clear();
}
if (gamma_ramp && gamma_version_ != gamma_ramp->version) {
gamma_version_ = gamma_ramp->version;
for (uint32_t i = 0; i < DXMT_GAMMA_CP_COUNT; i++) {
gamma_lut_rgba_[i * 4 + 0] = std::clamp(gamma_ramp->red[i], 0.f, 1.f);
gamma_lut_rgba_[i * 4 + 1] = std::clamp(gamma_ramp->green[i], 0.f, 1.f);
gamma_lut_rgba_[i * 4 + 2] = std::clamp(gamma_ramp->blue[i], 0.f, 1.f);
gamma_lut_rgba_[i * 4 + 3] = 1.0f;
}
gamma_lut_texture_.replaceRegion(
{0, 0, 0}, {DXMT_GAMMA_CP_COUNT, 1, 1}, 0, 0,
gamma_lut_rgba_.data(),
DXMT_GAMMA_CP_COUNT * sizeof(float) * 4,
0);
pso_valid.clear();
}
}

Presenter::PresentState
Presenter::synchronizeLayerProperties() {
uint64_t display_setting_version = 0;
Expand All @@ -84,7 +120,7 @@ Presenter::synchronizeLayerProperties() {
: nullptr;
if (unlikely(!pso_valid.test_and_set())) {
frame_presented_.wait(frame_requested_);
buildRenderPipelineState(final_colorspace == WMTColorSpaceHDR_PQ, is_hdr && hdr_metadata != nullptr, sample_count_ > 1);
buildRenderPipelineState(final_colorspace == WMTColorSpaceHDR_PQ, is_hdr && hdr_metadata != nullptr, sample_count_ > 1, gamma_version_ != 0);
layer_.setProps(layer_props_);
layer_.setColorSpace(final_colorspace);
}
Expand Down Expand Up @@ -128,6 +164,7 @@ Presenter::encodeCommands(
if (fence)
encoder.waitForFence(fence, WMTRenderStageFragment);
encoder.setFragmentTexture(backbuffer, 0);
encoder.setFragmentTexture(gamma_lut_texture_, 1);

double width = layer_props_.drawable_width;
double height = layer_props_.drawable_height;
Expand All @@ -151,15 +188,16 @@ constexpr uint32_t kPresentFCIndex_HDRPQ = 0x101;
constexpr uint32_t kPresentFCIndex_WithHDRMetadata = 0x102;
constexpr uint32_t kPresentFCIndex_BackbufferIsSRGB = 0x103;
constexpr uint32_t kPresentFCIndex_BackbufferIsMS = 0x104;
constexpr uint32_t kPresentFCIndex_GammaEnabled = 0x105;

void
Presenter::buildRenderPipelineState(bool is_pq, bool with_hdr_metadata, bool is_ms) {
Presenter::buildRenderPipelineState(bool is_pq, bool with_hdr_metadata, bool is_ms, bool gamma_enable) {
auto pool = WMT::MakeAutoreleasePool();

auto library = lib_.getLibrary();

uint32_t true_data = true, false_data = false;
WMTFunctionConstant constants[5];
WMTFunctionConstant constants[6];
constants[0].data.set(&true_data);
constants[0].type = WMTDataTypeBool;
constants[0].index = kPresentFCIndex_BackbufferSizeMatched;
Expand All @@ -175,6 +213,9 @@ Presenter::buildRenderPipelineState(bool is_pq, bool with_hdr_metadata, bool is_
constants[4].data.set(is_ms ? &true_data : &false_data);
constants[4].type = WMTDataTypeBool;
constants[4].index = kPresentFCIndex_BackbufferIsMS;
constants[5].data.set(gamma_enable ? &true_data : &false_data);
constants[5].type = WMTDataTypeBool;
constants[5].index = kPresentFCIndex_GammaEnabled;

WMT::Reference<WMT::Error> error;
auto vs_present_quad = library.newFunction("vs_present_quad");
Expand Down
16 changes: 15 additions & 1 deletion src/dxmt/dxmt_presenter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ struct DXMTPresentMetadata {
float max_display_luminance;
};

constexpr uint32_t DXMT_GAMMA_CP_COUNT = 1024;

struct DXMTGammaRamp {
float red[DXMT_GAMMA_CP_COUNT];
float green[DXMT_GAMMA_CP_COUNT];
float blue[DXMT_GAMMA_CP_COUNT];
uint64_t version;
};

class Presenter : public RcObject {
public:
Presenter(
Expand All @@ -28,6 +37,8 @@ class Presenter : public RcObject {

void changeHDRMetadata(const WMTHDRMetadata *metadata);

void changeGammaRamp(const DXMTGammaRamp *gamma_ramp);

class PresentState {
public:
DXMTPresentMetadata metadata;
Expand Down Expand Up @@ -58,7 +69,7 @@ class Presenter : public RcObject {
encodeCommands(WMT::CommandBuffer cmdbuf, WMT::Fence fence, WMT::Texture backbuffer, DXMTPresentMetadata metadata);

private:
void buildRenderPipelineState(bool is_pq, bool with_hdr_metadata, bool is_ms);
void buildRenderPipelineState(bool is_pq, bool with_hdr_metadata, bool is_ms, bool gamma_enable);

WMT::Device device_;
WMT::MetalLayer layer_;
Expand All @@ -73,6 +84,9 @@ class Presenter : public RcObject {
WMTColorSpace display_colorspace_ = WMTColorSpaceSRGB;
WMTHDRMetadata display_hdr_metadata_;
WMTEDRValue display_edr_value_{0.0, 1.0};
uint64_t gamma_version_ = 0;
std::array<float, DXMT_GAMMA_CP_COUNT * 4> gamma_lut_rgba_;
WMT::Reference<WMT::Texture> gamma_lut_texture_;
WMT::Reference<WMT::RenderPipelineState> present_blit_;
WMT::Reference<WMT::RenderPipelineState> present_scale_;
std::atomic_flag pso_valid = 0;
Expand Down