mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-06-05 06:14:25 +00:00
[idd] driver: implement postprocess filters
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
Some checks failed
build / client (Debug, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Debug, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:clang cxx:clang++], xdg-shell) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], libdecor) (push) Has been cancelled
build / client (Release, map[cc:gcc cxx:g++], xdg-shell) (push) Has been cancelled
build / module (push) Has been cancelled
build / host-linux (push) Has been cancelled
build / host-windows-cross (push) Has been cancelled
build / host-windows-native (push) Has been cancelled
build / idd (push) Has been cancelled
build / obs (clang) (push) Has been cancelled
build / obs (gcc) (push) Has been cancelled
build / docs (push) Has been cancelled
This commit is contained in:
committed by
Geoffrey McRae
parent
a59040f0be
commit
1b7c00dc82
@@ -93,6 +93,11 @@ class CD3D12CommandQueue
|
||||
bool IsReady () const { return !m_pending ; }
|
||||
HANDLE GetEvent() const { return m_event.Get(); }
|
||||
|
||||
void WaitFor(CD3D12CommandQueue& queue)
|
||||
{
|
||||
m_queue->Wait(queue.m_fence.Get(), queue.m_fenceValue);
|
||||
}
|
||||
|
||||
ComPtr<ID3D12CommandQueue > GetCmdQueue() { return m_queue; }
|
||||
ComPtr<ID3D12GraphicsCommandList> GetGfxList() { return m_gfxList; }
|
||||
};
|
||||
|
||||
@@ -132,8 +132,9 @@ CD3D12Device::InitResult CD3D12Device::Init(CIVSHMEM &ivshmem, UINT64 &alignSize
|
||||
m_indirectCopy ? CD3D12CommandQueue::NORMAL : CD3D12CommandQueue::FAST))
|
||||
return InitResult::FAILURE;
|
||||
|
||||
//if (!m_computeQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COMPUTE, L"Compute"))
|
||||
//return InitResult::FAILURE;
|
||||
if (!m_computeQueue.Init(m_device.Get(), D3D12_COMMAND_LIST_TYPE_COMPUTE, L"Compute",
|
||||
CD3D12CommandQueue::FAST))
|
||||
return InitResult::FAILURE;
|
||||
|
||||
DEBUG_INFO("Created CD3D12Device");
|
||||
return InitResult::SUCCESS;
|
||||
@@ -212,4 +213,20 @@ CD3D12CommandQueue * CD3D12Device::GetCopyQueue()
|
||||
|
||||
DEBUG_ERROR("Failed to get a copy queue");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CD3D12CommandQueue * CD3D12Device::GetComputeQueue()
|
||||
{
|
||||
for (int c = 0; c < 100; ++c)
|
||||
{
|
||||
if (m_computeQueue.IsReady())
|
||||
{
|
||||
m_computeQueue.Reset();
|
||||
return &m_computeQueue;
|
||||
}
|
||||
Sleep(1);
|
||||
}
|
||||
|
||||
DEBUG_ERROR("Failed to get a compute queue");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -74,5 +74,5 @@ struct CD3D12Device
|
||||
bool IsIndirectCopy() { return m_indirectCopy; }
|
||||
|
||||
CD3D12CommandQueue * GetCopyQueue();
|
||||
CD3D12CommandQueue & GetComputeQueue() { return m_computeQueue; }
|
||||
};
|
||||
CD3D12CommandQueue * GetComputeQueue();
|
||||
};
|
||||
|
||||
@@ -803,7 +803,8 @@ void CIndirectDeviceContext::LGMPTimer()
|
||||
}
|
||||
|
||||
CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrameBuffer(
|
||||
unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format, const RECT * dirtyRects, unsigned nbDirtyRects)
|
||||
unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat,
|
||||
const RECT * dirtyRects, unsigned nbDirtyRects)
|
||||
{
|
||||
PreparedFrameBuffer result = {};
|
||||
|
||||
@@ -811,15 +812,20 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
return result;
|
||||
|
||||
if (InterlockedCompareExchange(&m_recoverModeUpdateSwapChain, 0, 0) &&
|
||||
width == m_setMode.width && height == m_setMode.height)
|
||||
srcFormat.width == m_setMode.width && srcFormat.height == m_setMode.height)
|
||||
InterlockedExchange(&m_recoverModeUpdateSwapChain, 0);
|
||||
|
||||
if (m_width != width || m_height != height || m_pitch != pitch || m_format != format)
|
||||
if (m_width != dstFormat.desc.Width ||
|
||||
m_height != dstFormat.desc.Height ||
|
||||
m_pitch != pitch ||
|
||||
m_format != dstFormat.desc.Format ||
|
||||
m_frameType != dstFormat.format)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_format = format;
|
||||
m_pitch = pitch;
|
||||
m_width = (unsigned)dstFormat.desc.Width;
|
||||
m_height = dstFormat.desc.Height;
|
||||
m_format = dstFormat.desc.Format;
|
||||
m_frameType = dstFormat.format;
|
||||
m_pitch = pitch;
|
||||
++m_formatVer;
|
||||
}
|
||||
|
||||
@@ -832,36 +838,38 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
while (lgmpHostQueuePending(m_frameQueue) == LGMP_Q_FRAME_LEN)
|
||||
Sleep(0);
|
||||
|
||||
int bpp = 4;
|
||||
switch (format)
|
||||
if (dstFormat.format == FRAME_TYPE_INVALID)
|
||||
{
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM : fi->type = FRAME_TYPE_BGRA ; break;
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM : fi->type = FRAME_TYPE_RGBA ; break;
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM : fi->type = FRAME_TYPE_RGBA10 ; break;
|
||||
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT:
|
||||
fi->type = FRAME_TYPE_RGBA16F;
|
||||
bpp = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unsuppoted DXGI format 0x%08x", format);
|
||||
return result;
|
||||
DEBUG_ERROR("Unsupported frame format, skipping frame");
|
||||
return result;
|
||||
}
|
||||
|
||||
const unsigned maxRows = (unsigned)(m_maxFrameSize / pitch);
|
||||
const int bpp = dstFormat.format == FRAME_TYPE_RGBA16F ? 8 : 4;
|
||||
KVMFRFrameFlags flags =
|
||||
(dstFormat.hdr ? FRAME_FLAG_HDR : 0) |
|
||||
(dstFormat.hdrPQ ? FRAME_FLAG_HDR_PQ : 0);
|
||||
|
||||
if (dstFormat.format == FRAME_TYPE_RGBA16F)
|
||||
flags |= FRAME_FLAG_HDR;
|
||||
|
||||
if (maxRows < dstFormat.desc.Height)
|
||||
flags |= FRAME_FLAG_TRUNCATED;
|
||||
|
||||
fi->formatVer = m_formatVer;
|
||||
fi->frameSerial = m_frameSerial++;
|
||||
fi->screenWidth = width;
|
||||
fi->screenHeight = height;
|
||||
fi->dataWidth = width;
|
||||
fi->dataHeight = height;
|
||||
fi->frameWidth = width;
|
||||
fi->frameHeight = height;
|
||||
fi->screenWidth = srcFormat.width;
|
||||
fi->screenHeight = srcFormat.height;
|
||||
fi->dataWidth = (unsigned)dstFormat.desc.Width;
|
||||
fi->dataHeight = min(maxRows, dstFormat.desc.Height);
|
||||
fi->frameWidth = dstFormat.width;
|
||||
fi->frameHeight = dstFormat.height;
|
||||
fi->stride = pitch / bpp;
|
||||
fi->pitch = pitch;
|
||||
// fi->offset is initialized at startup
|
||||
fi->flags = 0;
|
||||
fi->flags = flags;
|
||||
fi->rotation = FRAME_ROT_0;
|
||||
fi->type = dstFormat.format;
|
||||
fi->damageRectsCount = 0;
|
||||
if (nbDirtyRects <= ARRAYSIZE(fi->damageRects))
|
||||
{
|
||||
@@ -875,7 +883,7 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
}
|
||||
}
|
||||
|
||||
FrameBuffer* fb = m_frameBuffer[m_frameIndex];
|
||||
FrameBuffer* fb = m_frameBuffer[m_frameIndex];
|
||||
fb->wp = 0;
|
||||
|
||||
lgmpHostQueuePost(m_frameQueue, 0, m_frameMemory[m_frameIndex]);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "CIVSHMEM.h"
|
||||
#include "CSettings.h"
|
||||
#include "CEdid.h"
|
||||
#include "CPostProcessor.h"
|
||||
|
||||
extern "C" {
|
||||
#include "lgmp/host.h"
|
||||
@@ -83,6 +84,7 @@ private:
|
||||
unsigned m_height = 0;
|
||||
unsigned m_pitch = 0;
|
||||
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
|
||||
FrameType m_frameType = FRAME_TYPE_INVALID;
|
||||
bool m_hasFrame = false;
|
||||
|
||||
UINT m_iddCxVersion = 0;
|
||||
@@ -148,7 +150,7 @@ public:
|
||||
uint8_t* mem;
|
||||
};
|
||||
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned width, unsigned height, unsigned pitch, DXGI_FORMAT format, const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||
PreparedFrameBuffer PrepareFrameBuffer(unsigned pitch, const D12FrameFormat& srcFormat, const D12FrameFormat& dstFormat, const RECT * dirtyRects, unsigned nbDirtyRects);
|
||||
void WriteFrameBuffer(unsigned frameIndex, void* src, size_t offset, size_t len, bool setWritePos) const;
|
||||
void FinalizeFrameBuffer(unsigned frameIndex) const;
|
||||
|
||||
|
||||
143
idd/LGIdd/CPostProcessor.cpp
Normal file
143
idd/LGIdd/CPostProcessor.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include "CPostProcessor.h"
|
||||
|
||||
#include "CD3D12Device.h"
|
||||
#include "CDebug.h"
|
||||
#include "effect/CDownsampleEffect.h"
|
||||
#include "effect/CHDR16to10Effect.h"
|
||||
#include "effect/CRGB24Effect.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
bool CPostProcessor::Init(std::shared_ptr<CD3D12Device> dx12Device)
|
||||
{
|
||||
m_dx12Device = dx12Device;
|
||||
m_device = dx12Device->GetDevice();
|
||||
m_effects.clear();
|
||||
|
||||
std::unique_ptr<CDownsampleEffect> downsample(new CDownsampleEffect());
|
||||
if (downsample->Init(m_device))
|
||||
{
|
||||
DEBUG_INFO("Created post-processing effect: %s", downsample->GetName());
|
||||
m_effects.push_back(std::move(downsample));
|
||||
}
|
||||
|
||||
std::unique_ptr<CHDR16to10Effect> hdr16to10(new CHDR16to10Effect());
|
||||
if (hdr16to10->Init(m_device))
|
||||
{
|
||||
DEBUG_INFO("Created post-processing effect: %s", hdr16to10->GetName());
|
||||
m_effects.push_back(std::move(hdr16to10));
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
std::unique_ptr<CRGB24Effect> rgb24(new CRGB24Effect());
|
||||
if (rgb24->Init(m_device))
|
||||
{
|
||||
DEBUG_INFO("Created post-processing effect: %s", rgb24->GetName());
|
||||
m_effects.push_back(std::move(rgb24));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPostProcessor::Reset()
|
||||
{
|
||||
m_effects.clear();
|
||||
m_dx12Device.reset();
|
||||
m_device.Reset();
|
||||
m_srcFormat = {};
|
||||
m_dstFormat = {};
|
||||
m_effectsActive = false;
|
||||
}
|
||||
|
||||
bool CPostProcessor::Configure(const D12FrameFormat& srcFormat, bool * formatChanged)
|
||||
{
|
||||
if (formatChanged)
|
||||
*formatChanged = false;
|
||||
|
||||
if (srcFormat.desc.Width == m_srcFormat.desc.Width &&
|
||||
srcFormat.desc.Height == m_srcFormat.desc.Height &&
|
||||
srcFormat.desc.Format == m_srcFormat.desc.Format &&
|
||||
srcFormat.format == m_srcFormat.format &&
|
||||
srcFormat.width == m_srcFormat.width &&
|
||||
srcFormat.height == m_srcFormat.height &&
|
||||
srcFormat.hdr == m_srcFormat.hdr &&
|
||||
srcFormat.hdrPQ == m_srcFormat.hdrPQ)
|
||||
return true;
|
||||
|
||||
D12FrameFormat oldDst = m_dstFormat;
|
||||
D12FrameFormat cur = srcFormat;
|
||||
m_srcFormat = srcFormat;
|
||||
m_effectsActive = false;
|
||||
|
||||
for (const auto& effect : m_effects)
|
||||
{
|
||||
D12FrameFormat dst = cur;
|
||||
switch (effect->SetFormat(m_device, cur, dst))
|
||||
{
|
||||
case PostProcessStatus::SUCCESS:
|
||||
effect->Enabled = true;
|
||||
m_effectsActive = true;
|
||||
cur = dst;
|
||||
DEBUG_INFO("Post-processing effect active: %s", effect->GetName());
|
||||
break;
|
||||
|
||||
case PostProcessStatus::BYPASS_EFFECT:
|
||||
effect->Enabled = false;
|
||||
break;
|
||||
|
||||
case PostProcessStatus::FAILED:
|
||||
DEBUG_ERROR("Failed to configure post-processing effect: %s", effect->GetName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
m_dstFormat = cur;
|
||||
if (formatChanged)
|
||||
*formatChanged = oldDst.desc.Width != m_dstFormat.desc.Width ||
|
||||
oldDst.desc.Height != m_dstFormat.desc.Height ||
|
||||
oldDst.desc.Format != m_dstFormat.desc.Format ||
|
||||
oldDst.format != m_dstFormat.format ||
|
||||
oldDst.width != m_dstFormat.width ||
|
||||
oldDst.height != m_dstFormat.height ||
|
||||
oldDst.hdr != m_dstFormat.hdr ||
|
||||
oldDst.hdrPQ != m_dstFormat.hdrPQ;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPostProcessor::AdjustFrameDamage(RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||
{
|
||||
for (const auto& effect : m_effects)
|
||||
if (effect->Enabled)
|
||||
effect->AdjustDamage(dirtyRects, nbDirtyRects);
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> CPostProcessor::Run(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects)
|
||||
{
|
||||
ComPtr<ID3D12Resource> next = src;
|
||||
for (const auto& effect : m_effects)
|
||||
{
|
||||
if (!effect->Enabled)
|
||||
continue;
|
||||
|
||||
//DEBUG_TRACE("Run post-processing effect: %s", effect->GetName());
|
||||
effect->AdjustDamage(dirtyRects, nbDirtyRects);
|
||||
next = effect->Run(m_device, commandList, next, dirtyRects, nbDirtyRects);
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
84
idd/LGIdd/CPostProcessor.h
Normal file
84
idd/LGIdd/CPostProcessor.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wrl/client.h>
|
||||
#include <d3d12.h>
|
||||
#include <dxgi1_5.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
struct CD3D12Device;
|
||||
|
||||
extern "C" {
|
||||
#include "common/types.h"
|
||||
}
|
||||
|
||||
using namespace Microsoft::WRL;
|
||||
|
||||
enum class PostProcessStatus
|
||||
{
|
||||
SUCCESS,
|
||||
BYPASS_EFFECT,
|
||||
FAILED
|
||||
};
|
||||
|
||||
struct D12FrameFormat
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
FrameType format = FRAME_TYPE_INVALID;
|
||||
bool hdr = false;
|
||||
bool hdrPQ = false;
|
||||
};
|
||||
|
||||
class CPostProcessEffect
|
||||
{
|
||||
public:
|
||||
virtual ~CPostProcessEffect() {}
|
||||
virtual const char * GetName() const = 0;
|
||||
virtual PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst) = 0;
|
||||
virtual void AdjustDamage(RECT dirtyRects[], unsigned * nbDirtyRects) { UNREFERENCED_PARAMETER(dirtyRects); UNREFERENCED_PARAMETER(nbDirtyRects); }
|
||||
virtual ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects) = 0;
|
||||
bool Enabled = false;
|
||||
};
|
||||
|
||||
class CPostProcessor
|
||||
{
|
||||
private:
|
||||
std::shared_ptr<CD3D12Device> m_dx12Device;
|
||||
ComPtr<ID3D12Device3> m_device;
|
||||
std::vector<std::unique_ptr<CPostProcessEffect>> m_effects;
|
||||
D12FrameFormat m_srcFormat = {};
|
||||
D12FrameFormat m_dstFormat = {};
|
||||
bool m_effectsActive = false;
|
||||
|
||||
public:
|
||||
bool Init(std::shared_ptr<CD3D12Device> dx12Device);
|
||||
void Reset();
|
||||
|
||||
bool Configure(const D12FrameFormat& srcFormat, bool * formatChanged);
|
||||
void AdjustFrameDamage(RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||
ComPtr<ID3D12Resource> Run(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects);
|
||||
|
||||
const D12FrameFormat& GetOutputFormat() const { return m_dstFormat; }
|
||||
bool HasActiveEffects() const { return m_effectsActive; }
|
||||
};
|
||||
@@ -43,8 +43,8 @@ class CSettings
|
||||
bool GetExtraMode(DisplayMode & mode);
|
||||
unsigned GetDefaultRefresh() const;
|
||||
|
||||
std::wstring ReadStringValue(const wchar_t* name, const wchar_t* defaultValue);
|
||||
bool ReadBoolValue(const wchar_t* name, bool defaultValue);
|
||||
std::wstring ReadStringValue(const wchar_t* name, const wchar_t* defaultValue = nullptr);
|
||||
bool ReadBoolValue(const wchar_t* name, bool defaultValue = false);
|
||||
|
||||
private:
|
||||
DisplayModes m_displayModes;
|
||||
|
||||
@@ -34,6 +34,8 @@ CSwapChainProcessor::CSwapChainProcessor(IDDCX_MONITOR monitor, CIndirectDeviceC
|
||||
{
|
||||
m_resPool.Init(dx11Device, dx12Device);
|
||||
m_fbPool.Init(this);
|
||||
if (!m_postProcessor.Init(dx12Device))
|
||||
DEBUG_ERROR("Failed to initialize post processor");
|
||||
|
||||
m_terminateEvent.Attach(CreateEvent(nullptr, FALSE, FALSE, nullptr));
|
||||
m_thread[0].Attach(CreateThread(nullptr, 0, _SwapChainThread, this, 0, nullptr));
|
||||
@@ -50,6 +52,7 @@ CSwapChainProcessor::~CSwapChainProcessor()
|
||||
if (m_thread[1].Get())
|
||||
WaitForSingleObject(m_thread[1].Get(), INFINITE);
|
||||
|
||||
m_postProcessor.Reset();
|
||||
m_resPool.Reset();
|
||||
m_fbPool.Reset();
|
||||
delete[] m_shapeBuffer;
|
||||
@@ -268,6 +271,44 @@ static void CopyDirtyRect(ComPtr<ID3D12GraphicsCommandList> list,
|
||||
list->CopyTextureRegion(dstLoc, box.left, box.top, 0, srcLoc, &box);
|
||||
}
|
||||
|
||||
static bool ClipDirtyRect(RECT& rect, const D3D12_RESOURCE_DESC& desc)
|
||||
{
|
||||
const LONG maxRight = (LONG)desc.Width;
|
||||
const LONG maxBottom = (LONG)desc.Height;
|
||||
|
||||
if (rect.left < 0 ) rect.left = 0;
|
||||
if (rect.top < 0 ) rect.top = 0;
|
||||
if (rect.right > maxRight ) rect.right = maxRight;
|
||||
if (rect.bottom > maxBottom) rect.bottom = maxBottom;
|
||||
|
||||
return rect.left < rect.right && rect.top < rect.bottom;
|
||||
}
|
||||
|
||||
static void ClipDirtyRects(RECT dirtyRects[], unsigned * nbDirtyRects,
|
||||
const D3D12_RESOURCE_DESC& desc)
|
||||
{
|
||||
unsigned out = 0;
|
||||
for (unsigned i = 0; i < *nbDirtyRects; ++i)
|
||||
{
|
||||
RECT rect = dirtyRects[i];
|
||||
if (ClipDirtyRect(rect, desc))
|
||||
dirtyRects[out++] = rect;
|
||||
}
|
||||
*nbDirtyRects = out;
|
||||
}
|
||||
|
||||
static FrameType GetFrameType(DXGI_FORMAT format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case DXGI_FORMAT_B8G8R8A8_UNORM : return FRAME_TYPE_BGRA;
|
||||
case DXGI_FORMAT_R8G8B8A8_UNORM : return FRAME_TYPE_RGBA;
|
||||
case DXGI_FORMAT_R10G10B10A2_UNORM : return FRAME_TYPE_RGBA10;
|
||||
case DXGI_FORMAT_R16G16B16A16_FLOAT: return FRAME_TYPE_RGBA16F;
|
||||
default : return FRAME_TYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer, unsigned dirtyRectCount)
|
||||
{
|
||||
ComPtr<ID3D11Texture2D> texture;
|
||||
@@ -314,37 +355,47 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
srcRes->SetDirtyRects(dirtyRects, dirtyOut.DirtyRectOutCount);
|
||||
}
|
||||
|
||||
D3D12_RESOURCE_DESC desc = srcRes->GetRes()->GetDesc();
|
||||
D3D12_RESOURCE_DESC srcDesc = srcRes->GetRes()->GetDesc();
|
||||
D12FrameFormat srcFormat = {};
|
||||
srcFormat.desc = srcDesc;
|
||||
srcFormat.width = (unsigned)srcDesc.Width;
|
||||
srcFormat.height = srcDesc.Height;
|
||||
srcFormat.format = GetFrameType(srcDesc.Format);
|
||||
srcFormat.hdr = srcDesc.Format == DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
srcFormat.hdrPQ = false;
|
||||
|
||||
bool postProcessFormatChanged = false;
|
||||
if (!m_postProcessor.Configure(srcFormat, &postProcessFormatChanged))
|
||||
return false;
|
||||
|
||||
if (postProcessFormatChanged)
|
||||
m_nbDirtyRects = 0;
|
||||
|
||||
const D12FrameFormat& dstFormat = m_postProcessor.GetOutputFormat();
|
||||
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
|
||||
m_dx12Device->GetDevice()->GetCopyableFootprints(
|
||||
&desc,
|
||||
&dstFormat.desc,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
&layout,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
auto buffer = m_devContext->PrepareFrameBuffer(
|
||||
(int)desc.Width,
|
||||
(int)desc.Height,
|
||||
(int)layout.Footprint.RowPitch,
|
||||
desc.Format,
|
||||
srcRes->GetDirtyRects(),
|
||||
srcRes->GetDirtyRectCount());
|
||||
|
||||
if (!buffer.mem)
|
||||
return false;
|
||||
|
||||
CFrameBufferResource * fbRes = m_fbPool.Get(buffer,
|
||||
(size_t)layout.Footprint.RowPitch * desc.Height);
|
||||
|
||||
if (!fbRes)
|
||||
RECT currentDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||
RECT frameDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||
unsigned nbDirtyRects = srcRes->GetDirtyRectCount();
|
||||
if (nbDirtyRects > ARRAYSIZE(currentDirtyRects))
|
||||
nbDirtyRects = 0;
|
||||
else
|
||||
{
|
||||
DEBUG_ERROR("Failed to get a CFrameBufferResource from the pool");
|
||||
return false;
|
||||
memcpy(currentDirtyRects, srcRes->GetDirtyRects(), nbDirtyRects * sizeof(*currentDirtyRects));
|
||||
memcpy(frameDirtyRects, currentDirtyRects, nbDirtyRects * sizeof(*frameDirtyRects));
|
||||
}
|
||||
unsigned frameDirtyRectCount = nbDirtyRects;
|
||||
m_postProcessor.AdjustFrameDamage(frameDirtyRects, &frameDirtyRectCount);
|
||||
|
||||
auto copyQueue = m_dx12Device->GetCopyQueue();
|
||||
if (!copyQueue)
|
||||
@@ -353,10 +404,53 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
return false;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> copySrcResource = srcRes->GetRes();
|
||||
CD3D12CommandQueue * computeQueue = nullptr;
|
||||
if (m_postProcessor.HasActiveEffects())
|
||||
{
|
||||
computeQueue = m_dx12Device->GetComputeQueue();
|
||||
if (!computeQueue)
|
||||
{
|
||||
DEBUG_ERROR("Failed to get a ComputeQueue");
|
||||
return false;
|
||||
}
|
||||
|
||||
srcRes->Sync(*computeQueue);
|
||||
copySrcResource = m_postProcessor.Run(
|
||||
computeQueue->GetGfxList(), copySrcResource,
|
||||
currentDirtyRects, &nbDirtyRects);
|
||||
|
||||
computeQueue->Execute();
|
||||
copyQueue->WaitFor(*computeQueue);
|
||||
}
|
||||
else
|
||||
srcRes->Sync(*copyQueue);
|
||||
|
||||
ClipDirtyRects(currentDirtyRects, &nbDirtyRects, dstFormat.desc);
|
||||
|
||||
auto buffer = m_devContext->PrepareFrameBuffer(
|
||||
(unsigned)layout.Footprint.RowPitch,
|
||||
srcFormat,
|
||||
dstFormat,
|
||||
frameDirtyRects,
|
||||
frameDirtyRectCount);
|
||||
|
||||
if (!buffer.mem)
|
||||
return false;
|
||||
|
||||
CFrameBufferResource * fbRes = m_fbPool.Get(buffer,
|
||||
(size_t)layout.Footprint.RowPitch * dstFormat.desc.Height);
|
||||
|
||||
if (!fbRes)
|
||||
{
|
||||
DEBUG_ERROR("Failed to get a CFrameBufferResource from the pool");
|
||||
return false;
|
||||
}
|
||||
|
||||
copyQueue->SetCompletionCallback(&CompletionFunction, this, fbRes);
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
|
||||
srcLoc.pResource = srcRes->GetRes().Get();
|
||||
srcLoc.pResource = copySrcResource.Get();
|
||||
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
srcLoc.SubresourceIndex = 0;
|
||||
|
||||
@@ -365,11 +459,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dstLoc.PlacedFootprint = layout;
|
||||
|
||||
srcRes->Sync(*copyQueue);
|
||||
|
||||
const RECT * currentDirtyRects = srcRes->GetDirtyRects();
|
||||
unsigned nbDirtyRects = srcRes->GetDirtyRectCount();
|
||||
if (IsFullDamage(currentDirtyRects, nbDirtyRects, desc) ||
|
||||
if (IsFullDamage(currentDirtyRects, nbDirtyRects, dstFormat.desc) ||
|
||||
nbDirtyRects > KVMFR_MAX_DAMAGE_RECTS || m_nbDirtyRects == 0)
|
||||
{
|
||||
copyQueue->GetGfxList()->CopyTextureRegion(
|
||||
@@ -383,7 +473,11 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
else
|
||||
{
|
||||
for (const RECT * rect = m_dirtyRects; rect < m_dirtyRects + m_nbDirtyRects; ++rect)
|
||||
CopyDirtyRect(copyQueue->GetGfxList(), &dstLoc, &srcLoc, *rect);
|
||||
{
|
||||
RECT clipped = *rect;
|
||||
if (ClipDirtyRect(clipped, dstFormat.desc))
|
||||
CopyDirtyRect(copyQueue->GetGfxList(), &dstLoc, &srcLoc, clipped);
|
||||
}
|
||||
|
||||
for (const RECT * rect = currentDirtyRects; rect < currentDirtyRects + nbDirtyRects; ++rect)
|
||||
CopyDirtyRect(copyQueue->GetGfxList(), &dstLoc, &srcLoc, *rect);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "CIndirectDeviceContext.h"
|
||||
#include "CInteropResourcePool.h"
|
||||
#include "CFrameBufferPool.h"
|
||||
#include "CPostProcessor.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <wrl.h>
|
||||
@@ -47,6 +48,7 @@ private:
|
||||
|
||||
CInteropResourcePool m_resPool;
|
||||
CFrameBufferPool m_fbPool;
|
||||
CPostProcessor m_postProcessor;
|
||||
|
||||
Wrappers::HandleT<Wrappers::HandleTraits::HANDLENullTraits> m_thread[2];
|
||||
Wrappers::Event m_terminateEvent;
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
<ClCompile Include="CIVSHMEM.cpp" />
|
||||
<ClCompile Include="CPipeServer.cpp" />
|
||||
<ClCompile Include="CPlatformInfo.cpp" />
|
||||
<ClCompile Include="CPostProcessor.cpp" />
|
||||
<ClCompile Include="effect\CComputeEffect.cpp" />
|
||||
<ClCompile Include="effect\CDownsampleEffect.cpp" />
|
||||
<ClCompile Include="effect\CHDR16to10Effect.cpp" />
|
||||
<ClCompile Include="effect\CRGB24Effect.cpp" />
|
||||
<ClCompile Include="CSettings.cpp" />
|
||||
<ClCompile Include="CSwapChainProcessor.cpp" />
|
||||
<ClCompile Include="CD3D12Device.cpp" />
|
||||
@@ -55,6 +60,11 @@
|
||||
<ClInclude Include="CIVSHMEM.h" />
|
||||
<ClInclude Include="CPipeServer.h" />
|
||||
<ClInclude Include="CPlatformInfo.h" />
|
||||
<ClInclude Include="CPostProcessor.h" />
|
||||
<ClInclude Include="effect\CComputeEffect.h" />
|
||||
<ClInclude Include="effect\CDownsampleEffect.h" />
|
||||
<ClInclude Include="effect\CHDR16to10Effect.h" />
|
||||
<ClInclude Include="effect\CRGB24Effect.h" />
|
||||
<ClInclude Include="CSettings.h" />
|
||||
<ClInclude Include="CSwapChainProcessor.h" />
|
||||
<ClInclude Include="CD3D12Device.h" />
|
||||
@@ -179,7 +189,7 @@
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
<DriverSign>
|
||||
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
|
||||
@@ -194,7 +204,7 @@
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\..\repos\LGMP\lgmp\include;$(ProjectDir)..\..\vendor;$(ProjectDir)..\..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
<DriverSign>
|
||||
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
|
||||
@@ -209,7 +219,7 @@
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)LGCommon;$(SolutionDir)..\repos\LGMP\lgmp\include;$(SolutionDir)..\vendor;$(SolutionDir)..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
<DriverSign>
|
||||
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
|
||||
@@ -224,7 +234,7 @@
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)LGCommon;$(SolutionDir)..\repos\LGMP\lgmp\include;$(SolutionDir)..\vendor;$(SolutionDir)..\common\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);OneCoreUAP.lib;avrt.lib;d3d12.lib;d3dcompiler.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
<DriverSign>
|
||||
<FileDigestAlgorithm>SHA1</FileDigestAlgorithm>
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
|
||||
<Extensions>inf;inv;inx;mof;mc;</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\effect">
|
||||
<UniqueIdentifier>{52F1286F-0C64-41B9-92A9-4453C80B1001}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\effect">
|
||||
<UniqueIdentifier>{DB623F3B-5D6A-4F8C-8884-83588A1B58D2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
@@ -85,6 +91,21 @@
|
||||
<ClInclude Include="CSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CPostProcessor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CComputeEffect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CDownsampleEffect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CHDR16to10Effect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="effect\CRGB24Effect.h">
|
||||
<Filter>Header Files\effect</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
<ClInclude Include="$(SolutionDir)/LGCommon/*.h" />
|
||||
</ItemGroup>
|
||||
@@ -139,6 +160,21 @@
|
||||
<ClCompile Include="CSettings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CPostProcessor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CComputeEffect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CDownsampleEffect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CHDR16to10Effect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="effect\CRGB24Effect.cpp">
|
||||
<Filter>Source Files\effect</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(SolutionDir)LGCommon/*.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
165
idd/LGIdd/effect/CComputeEffect.cpp
Normal file
165
idd/LGIdd/effect/CComputeEffect.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include "CComputeEffect.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <d3dcompiler.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace PostProcessUtil
|
||||
{
|
||||
bool CreateDefaultTexture(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_RESOURCE_DESC& desc, ComPtr<ID3D12Resource>& resource)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
heapProps.Type = D3D12_HEAP_TYPE_DEFAULT;
|
||||
heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
|
||||
heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
|
||||
heapProps.CreationNodeMask = 1;
|
||||
heapProps.VisibleNodeMask = 1;
|
||||
|
||||
HRESULT hr = device->CreateCommittedResource(
|
||||
&heapProps,
|
||||
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
|
||||
&desc,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&resource));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create post-processing destination texture");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CComputeEffect::InitCompute(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_DESCRIPTOR_RANGE * ranges, UINT rangeCount,
|
||||
const D3D12_STATIC_SAMPLER_DESC * samplers, UINT samplerCount,
|
||||
const char * shader)
|
||||
{
|
||||
D3D12_ROOT_PARAMETER rootParam = {};
|
||||
rootParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
|
||||
rootParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
rootParam.DescriptorTable.NumDescriptorRanges = rangeCount;
|
||||
rootParam.DescriptorTable.pDescriptorRanges = ranges;
|
||||
|
||||
D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc = {};
|
||||
rootSignatureDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1;
|
||||
rootSignatureDesc.Desc_1_0.NumParameters = 1;
|
||||
rootSignatureDesc.Desc_1_0.pParameters = &rootParam;
|
||||
rootSignatureDesc.Desc_1_0.NumStaticSamplers = samplerCount;
|
||||
rootSignatureDesc.Desc_1_0.pStaticSamplers = samplers;
|
||||
rootSignatureDesc.Desc_1_0.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
|
||||
|
||||
ComPtr<ID3DBlob> blob;
|
||||
ComPtr<ID3DBlob> error;
|
||||
HRESULT hr = D3D12SerializeVersionedRootSignature(
|
||||
&rootSignatureDesc, &blob, &error);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to serialize post-processing root signature");
|
||||
if (error)
|
||||
DEBUG_ERROR("%s", (const char *)error->GetBufferPointer());
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = device->CreateRootSignature(
|
||||
0,
|
||||
blob->GetBufferPointer(),
|
||||
blob->GetBufferSize(),
|
||||
IID_PPV_ARGS(&m_rootSignature));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create post-processing root signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
blob.Reset();
|
||||
error.Reset();
|
||||
hr = D3DCompile(
|
||||
shader,
|
||||
std::strlen(shader),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
"main",
|
||||
"cs_5_0",
|
||||
0,
|
||||
0,
|
||||
&blob,
|
||||
&error);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to compile post-processing shader");
|
||||
if (error)
|
||||
DEBUG_ERROR("%s", (const char *)error->GetBufferPointer());
|
||||
return false;
|
||||
}
|
||||
|
||||
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
|
||||
psoDesc.pRootSignature = m_rootSignature.Get();
|
||||
psoDesc.CS.pShaderBytecode = blob->GetBufferPointer();
|
||||
psoDesc.CS.BytecodeLength = blob->GetBufferSize();
|
||||
|
||||
hr = device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&m_pso));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create post-processing PSO");
|
||||
return false;
|
||||
}
|
||||
|
||||
UINT descriptorCount = 0;
|
||||
for (UINT i = 0; i < rangeCount; ++i)
|
||||
descriptorCount += ranges[i].NumDescriptors;
|
||||
|
||||
D3D12_DESCRIPTOR_HEAP_DESC heapDesc = {};
|
||||
heapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
|
||||
heapDesc.NumDescriptors = descriptorCount;
|
||||
heapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
|
||||
|
||||
hr = device->CreateDescriptorHeap(&heapDesc, IID_PPV_ARGS(&m_descHeap));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create post-processing descriptor heap");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CComputeEffect::Bind(const ComPtr<ID3D12GraphicsCommandList>& commandList)
|
||||
{
|
||||
ID3D12DescriptorHeap * heaps[] = { m_descHeap.Get() };
|
||||
commandList->SetDescriptorHeaps(1, heaps);
|
||||
commandList->SetPipelineState(m_pso.Get());
|
||||
commandList->SetComputeRootSignature(m_rootSignature.Get());
|
||||
commandList->SetComputeRootDescriptorTable(
|
||||
0, m_descHeap->GetGPUDescriptorHandleForHeapStart());
|
||||
}
|
||||
|
||||
void CComputeEffect::TransitionDst(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
|
||||
{
|
||||
D3D12_RESOURCE_BARRIER barrier = {};
|
||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||
barrier.Transition.pResource = m_dst.Get();
|
||||
barrier.Transition.StateBefore = before;
|
||||
barrier.Transition.StateAfter = after;
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
commandList->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
52
idd/LGIdd/effect/CComputeEffect.h
Normal file
52
idd/LGIdd/effect/CComputeEffect.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../CPostProcessor.h"
|
||||
|
||||
|
||||
#define POST_PROCESS_THREADS_STR "8"
|
||||
|
||||
namespace PostProcessUtil
|
||||
{
|
||||
static constexpr unsigned Threads = 8;
|
||||
|
||||
template<typename T>
|
||||
static constexpr T AlignTo(T value, T align)
|
||||
{
|
||||
return (value + (align - 1)) & ~(align - 1);
|
||||
}
|
||||
|
||||
bool CreateDefaultTexture(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_RESOURCE_DESC& desc, ComPtr<ID3D12Resource>& resource);
|
||||
}
|
||||
|
||||
class CComputeEffect : public CPostProcessEffect
|
||||
{
|
||||
protected:
|
||||
ComPtr<ID3D12RootSignature> m_rootSignature;
|
||||
ComPtr<ID3D12PipelineState> m_pso;
|
||||
ComPtr<ID3D12DescriptorHeap> m_descHeap;
|
||||
ComPtr<ID3D12Resource> m_dst;
|
||||
unsigned m_threadsX = 0;
|
||||
unsigned m_threadsY = 0;
|
||||
|
||||
bool InitCompute(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_DESCRIPTOR_RANGE * ranges, UINT rangeCount,
|
||||
const D3D12_STATIC_SAMPLER_DESC * samplers, UINT samplerCount,
|
||||
const char * shader);
|
||||
|
||||
void Bind(const ComPtr<ID3D12GraphicsCommandList>& commandList);
|
||||
|
||||
void TransitionDst(const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after);
|
||||
};
|
||||
269
idd/LGIdd/effect/CDownsampleEffect.cpp
Normal file
269
idd/LGIdd/effect/CDownsampleEffect.cpp
Normal file
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include "CDownsampleEffect.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "../CSettings.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cwchar>
|
||||
#include <cwctype>
|
||||
#include <cstring>
|
||||
|
||||
using namespace PostProcessUtil;
|
||||
|
||||
bool CDownsampleEffect::ParseRules(const std::wstring& value)
|
||||
{
|
||||
m_rules.clear();
|
||||
if (value.empty())
|
||||
return false;
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos < value.size())
|
||||
{
|
||||
size_t comma = value.find(L',', pos);
|
||||
std::wstring token = value.substr(pos,
|
||||
comma == std::wstring::npos ? std::wstring::npos : comma - pos);
|
||||
|
||||
while (!token.empty() && std::iswspace(token.front()))
|
||||
token.erase(token.begin());
|
||||
while (!token.empty() && std::iswspace(token.back()))
|
||||
token.pop_back();
|
||||
|
||||
if (!token.empty())
|
||||
{
|
||||
Rule rule = {};
|
||||
const wchar_t * start = token.c_str();
|
||||
if (*start == L'>')
|
||||
{
|
||||
rule.greater = true;
|
||||
++start;
|
||||
}
|
||||
|
||||
if (swscanf_s(start, L"%ux%u:%ux%u",
|
||||
&rule.x, &rule.y, &rule.targetX, &rule.targetY) != 4)
|
||||
{
|
||||
DEBUG_ERROR("Unable to parse IDD downsample rule");
|
||||
m_rules.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_INFO("idd:downsample rule: %ux%u -> %ux%u%s",
|
||||
rule.x, rule.y, rule.targetX, rule.targetY,
|
||||
rule.greater ? " (greater-than)" : "");
|
||||
m_rules.push_back(rule);
|
||||
}
|
||||
|
||||
if (comma == std::wstring::npos)
|
||||
break;
|
||||
pos = comma + 1;
|
||||
}
|
||||
|
||||
return !m_rules.empty();
|
||||
}
|
||||
|
||||
const CDownsampleEffect::Rule * CDownsampleEffect::MatchRule(
|
||||
unsigned width, unsigned height) const
|
||||
{
|
||||
const Rule * match = nullptr;
|
||||
for (const auto& rule : m_rules)
|
||||
if (( rule.greater && (width > rule.x || height > rule.y)) ||
|
||||
(!rule.greater && (width == rule.x && height == rule.y)))
|
||||
match = &rule;
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
bool CDownsampleEffect::Init(const ComPtr<ID3D12Device3>& device)
|
||||
{
|
||||
if (!ParseRules(g_settings.ReadStringValue(L"Downsample")))
|
||||
return false;
|
||||
|
||||
D3D12_STATIC_SAMPLER_DESC sampler = {};
|
||||
sampler.Filter = D3D12_FILTER_MIN_MAG_MIP_LINEAR;
|
||||
sampler.AddressU = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
sampler.AddressV = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
sampler.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP;
|
||||
sampler.ComparisonFunc = D3D12_COMPARISON_FUNC_NEVER;
|
||||
sampler.MaxLOD = D3D12_FLOAT32_MAX;
|
||||
sampler.ShaderRegister = 0;
|
||||
sampler.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL;
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE ranges[3] = {};
|
||||
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
|
||||
ranges[0].NumDescriptors = 1;
|
||||
ranges[0].BaseShaderRegister = 0;
|
||||
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
ranges[1].NumDescriptors = 1;
|
||||
ranges[1].BaseShaderRegister = 0;
|
||||
ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
ranges[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
ranges[2].NumDescriptors = 1;
|
||||
ranges[2].BaseShaderRegister = 0;
|
||||
ranges[2].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
|
||||
const char * shader =
|
||||
"cbuffer Constants : register(b0)\n"
|
||||
"{\n"
|
||||
" float Width;\n"
|
||||
" float Height;\n"
|
||||
"};\n"
|
||||
"Texture2D <float4> src : register(t0);\n"
|
||||
"RWTexture2D<float4> dst : register(u0);\n"
|
||||
"SamplerState ss : register(s0);\n"
|
||||
"[numthreads(" POST_PROCESS_THREADS_STR ", " POST_PROCESS_THREADS_STR ", 1)]\n"
|
||||
"void main(uint3 dt : SV_DispatchThreadID)\n"
|
||||
"{\n"
|
||||
" dst[dt.xy] = src.SampleLevel(ss,\n"
|
||||
" float2(\n"
|
||||
" (float(dt.x) + 0.5f) / Width,\n"
|
||||
" (float(dt.y) + 0.5f) / Height),\n"
|
||||
" 0);\n"
|
||||
"}\n";
|
||||
|
||||
if (!InitCompute(device, ranges, ARRAYSIZE(ranges), &sampler, 1, shader))
|
||||
return false;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
desc.Width = AlignTo(sizeof(m_consts),
|
||||
(size_t)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
|
||||
desc.Height = 1;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
|
||||
HRESULT hr = device->CreateCommittedResource(&heapProps,
|
||||
D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr, IID_PPV_ARGS(&m_constBuffer));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create Downsample constant buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PostProcessStatus CDownsampleEffect::SetFormat(
|
||||
const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||
{
|
||||
const Rule * rule = MatchRule((unsigned)src.desc.Width, src.desc.Height);
|
||||
if (!rule ||
|
||||
(rule->targetX == src.desc.Width && rule->targetY == src.desc.Height))
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
|
||||
D3D12_RESOURCE_DESC desc = src.desc;
|
||||
desc.Width = rule->targetX;
|
||||
desc.Height = rule->targetY;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
||||
return PostProcessStatus::FAILED;
|
||||
|
||||
m_consts.width = (float)rule->targetX;
|
||||
m_consts.height = (float)rule->targetY;
|
||||
|
||||
void * data = nullptr;
|
||||
D3D12_RANGE readRange = { 0, 0 };
|
||||
HRESULT hr = m_constBuffer->Map(0, &readRange, &data);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to map Downsample constant buffer");
|
||||
return PostProcessStatus::FAILED;
|
||||
}
|
||||
std::memcpy(data, &m_consts, sizeof(m_consts));
|
||||
m_constBuffer->Unmap(0, nullptr);
|
||||
|
||||
m_threadsX = ((unsigned)desc.Width + (Threads - 1)) / Threads;
|
||||
m_threadsY = ((unsigned)desc.Height + (Threads - 1)) / Threads;
|
||||
m_format = src.desc.Format;
|
||||
m_scaleX = (double)desc.Width / src.desc.Width;
|
||||
m_scaleY = (double)desc.Height / src.desc.Height;
|
||||
m_width = (unsigned)desc.Width;
|
||||
m_height = desc.Height;
|
||||
|
||||
dst.desc = desc;
|
||||
dst.width = (unsigned)desc.Width;
|
||||
dst.height = desc.Height;
|
||||
return PostProcessStatus::SUCCESS;
|
||||
}
|
||||
|
||||
void CDownsampleEffect::AdjustDamage(RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||
{
|
||||
for (RECT * rect = dirtyRects; rect < dirtyRects + *nbDirtyRects; ++rect)
|
||||
{
|
||||
unsigned width = (unsigned)std::ceil((double)(rect->right - rect->left) * m_scaleX);
|
||||
unsigned height = (unsigned)std::ceil((double)(rect->bottom - rect->top ) * m_scaleY);
|
||||
rect->left = (LONG)max(0.0, std::floor((double)rect->left * m_scaleX));
|
||||
rect->right = (LONG)min((double)m_width , (double)rect->left + width);
|
||||
rect->top = (LONG)max(0.0, std::floor((double)rect->top * m_scaleY));
|
||||
rect->bottom = (LONG)min((double)m_height, (double)rect->top + height);
|
||||
|
||||
if (rect->left > 0 ) rect->left -= 1;
|
||||
if (rect->top > 0 ) rect->top -= 1;
|
||||
if (rect->right < (LONG)m_width ) rect->right += 1;
|
||||
if (rect->bottom < (LONG)m_height ) rect->bottom += 1;
|
||||
}
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> CDownsampleEffect::Run(
|
||||
const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
m_descHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
const UINT inc = device->GetDescriptorHandleIncrementSize(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
||||
cbvDesc.BufferLocation = m_constBuffer->GetGPUVirtualAddress();
|
||||
cbvDesc.SizeInBytes = (UINT)AlignTo(sizeof(m_consts),
|
||||
(size_t)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
|
||||
device->CreateConstantBufferView(&cbvDesc, handle);
|
||||
handle.ptr += inc;
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = m_format;
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
device->CreateShaderResourceView(src.Get(), &srvDesc, handle);
|
||||
handle.ptr += inc;
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.Format = m_format;
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
device->CreateUnorderedAccessView(m_dst.Get(), nullptr, &uavDesc, handle);
|
||||
|
||||
Bind(commandList);
|
||||
commandList->Dispatch(m_threadsX, m_threadsY, 1);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
return m_dst;
|
||||
}
|
||||
62
idd/LGIdd/effect/CDownsampleEffect.h
Normal file
62
idd/LGIdd/effect/CDownsampleEffect.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CComputeEffect.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class CDownsampleEffect : public CComputeEffect
|
||||
{
|
||||
private:
|
||||
struct Rule
|
||||
{
|
||||
bool greater = false;
|
||||
unsigned x = 0;
|
||||
unsigned y = 0;
|
||||
unsigned targetX = 0;
|
||||
unsigned targetY = 0;
|
||||
};
|
||||
|
||||
struct Consts
|
||||
{
|
||||
float width;
|
||||
float height;
|
||||
} m_consts = {};
|
||||
|
||||
std::vector<Rule> m_rules;
|
||||
ComPtr<ID3D12Resource> m_constBuffer;
|
||||
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
|
||||
double m_scaleX = 1.0;
|
||||
double m_scaleY = 1.0;
|
||||
unsigned m_width = 0;
|
||||
unsigned m_height = 0;
|
||||
|
||||
bool ParseRules(const std::wstring& value);
|
||||
const Rule * MatchRule(unsigned width, unsigned height) const;
|
||||
|
||||
public:
|
||||
const char * GetName() const override { return "Downsample"; }
|
||||
|
||||
bool Init(const ComPtr<ID3D12Device3>& device);
|
||||
|
||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||
|
||||
void AdjustDamage(RECT dirtyRects[], unsigned * nbDirtyRects) override;
|
||||
|
||||
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects) override;
|
||||
};
|
||||
152
idd/LGIdd/effect/CHDR16to10Effect.cpp
Normal file
152
idd/LGIdd/effect/CHDR16to10Effect.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include "CHDR16to10Effect.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace PostProcessUtil;
|
||||
|
||||
bool CHDR16to10Effect::Init(const ComPtr<ID3D12Device3>& device)
|
||||
{
|
||||
D3D12_DESCRIPTOR_RANGE ranges[3] = {};
|
||||
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV;
|
||||
ranges[0].NumDescriptors = 1;
|
||||
ranges[0].BaseShaderRegister = 0;
|
||||
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
ranges[1].NumDescriptors = 1;
|
||||
ranges[1].BaseShaderRegister = 0;
|
||||
ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
ranges[2].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
ranges[2].NumDescriptors = 1;
|
||||
ranges[2].BaseShaderRegister = 0;
|
||||
ranges[2].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
|
||||
const char * shader =
|
||||
"cbuffer Constants : register(b0)\n"
|
||||
"{\n"
|
||||
" float SDRWhiteLevel;\n"
|
||||
"};\n"
|
||||
"Texture2D<float4> src : register(t0);\n"
|
||||
"RWTexture2D<float4> dst : register(u0);\n"
|
||||
"[numthreads(" POST_PROCESS_THREADS_STR ", " POST_PROCESS_THREADS_STR ", 1)]\n"
|
||||
"void main(uint3 dt : SV_DispatchThreadID)\n"
|
||||
"{\n"
|
||||
" dst[dt.xy] = float4(src[dt.xy].rgb * SDRWhiteLevel, src[dt.xy].a);\n"
|
||||
"}\n";
|
||||
|
||||
if (!InitCompute(device, ranges, ARRAYSIZE(ranges), nullptr, 0, shader))
|
||||
return false;
|
||||
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
heapProps.Type = D3D12_HEAP_TYPE_UPLOAD;
|
||||
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
desc.Width = AlignTo(sizeof(m_consts),
|
||||
(size_t)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
|
||||
desc.Height = 1;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
|
||||
HRESULT hr = device->CreateCommittedResource(&heapProps,
|
||||
D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ,
|
||||
nullptr, IID_PPV_ARGS(&m_constBuffer));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create HDR16to10 constant buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
void * data = nullptr;
|
||||
D3D12_RANGE readRange = { 0, 0 };
|
||||
hr = m_constBuffer->Map(0, &readRange, &data);
|
||||
if (FAILED(hr))
|
||||
return false;
|
||||
std::memcpy(data, &m_consts, sizeof(m_consts));
|
||||
m_constBuffer->Unmap(0, nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PostProcessStatus CHDR16to10Effect::SetFormat(
|
||||
const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||
{
|
||||
if (src.desc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT || !src.hdr)
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
|
||||
D3D12_RESOURCE_DESC desc = src.desc;
|
||||
desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
||||
return PostProcessStatus::FAILED;
|
||||
|
||||
m_threadsX = ((unsigned)desc.Width + (Threads - 1)) / Threads;
|
||||
m_threadsY = ((unsigned)desc.Height + (Threads - 1)) / Threads;
|
||||
|
||||
dst.desc = desc;
|
||||
dst.format = FRAME_TYPE_RGBA10;
|
||||
dst.hdr = true;
|
||||
dst.hdrPQ = false;
|
||||
return PostProcessStatus::SUCCESS;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> CHDR16to10Effect::Run(
|
||||
const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
m_descHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
const UINT inc = device->GetDescriptorHandleIncrementSize(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
|
||||
cbvDesc.BufferLocation = m_constBuffer->GetGPUVirtualAddress();
|
||||
cbvDesc.SizeInBytes = (UINT)AlignTo(sizeof(m_consts),
|
||||
(size_t)D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT);
|
||||
device->CreateConstantBufferView(&cbvDesc, handle);
|
||||
handle.ptr += inc;
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT;
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
device->CreateShaderResourceView(src.Get(), &srvDesc, handle);
|
||||
handle.ptr += inc;
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
device->CreateUnorderedAccessView(m_dst.Get(), nullptr, &uavDesc, handle);
|
||||
|
||||
Bind(commandList);
|
||||
commandList->Dispatch(m_threadsX, m_threadsY, 1);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
return m_dst;
|
||||
}
|
||||
37
idd/LGIdd/effect/CHDR16to10Effect.h
Normal file
37
idd/LGIdd/effect/CHDR16to10Effect.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CComputeEffect.h"
|
||||
|
||||
class CHDR16to10Effect : public CComputeEffect
|
||||
{
|
||||
private:
|
||||
struct Consts
|
||||
{
|
||||
float SDRWhiteLevel;
|
||||
} m_consts = { 1.0f };
|
||||
ComPtr<ID3D12Resource> m_constBuffer;
|
||||
|
||||
public:
|
||||
const char * GetName() const override { return "HDR16to10"; }
|
||||
|
||||
bool Init(const ComPtr<ID3D12Device3>& device);
|
||||
|
||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||
|
||||
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects) override;
|
||||
};
|
||||
123
idd/LGIdd/effect/CRGB24Effect.cpp
Normal file
123
idd/LGIdd/effect/CRGB24Effect.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#include "CRGB24Effect.h"
|
||||
|
||||
#include "../CSettings.h"
|
||||
|
||||
using namespace PostProcessUtil;
|
||||
|
||||
bool CRGB24Effect::Init(const ComPtr<ID3D12Device3>& device)
|
||||
{
|
||||
if (!g_settings.ReadBoolValue(L"AllowRGB24", false))
|
||||
return false;
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE ranges[2] = {};
|
||||
ranges[0].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV;
|
||||
ranges[0].NumDescriptors = 1;
|
||||
ranges[0].BaseShaderRegister = 0;
|
||||
ranges[0].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
ranges[1].RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV;
|
||||
ranges[1].NumDescriptors = 1;
|
||||
ranges[1].BaseShaderRegister = 0;
|
||||
ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
|
||||
const char * shader =
|
||||
"Texture2D <float4> src : register(t0);\n"
|
||||
"RWTexture2D<float4> dst : register(u0);\n"
|
||||
"[numthreads(" POST_PROCESS_THREADS_STR ", " POST_PROCESS_THREADS_STR ", 1)]\n"
|
||||
"void main(uint3 dt : SV_DispatchThreadID)\n"
|
||||
"{\n"
|
||||
" uint fstInputX = (dt.x * 4) / 3;\n"
|
||||
" float4 color0 = src[uint2(fstInputX, dt.y)];\n"
|
||||
" uint sndInputX = fstInputX + 1;\n"
|
||||
" float4 color3 = src[uint2(sndInputX, dt.y)];\n"
|
||||
" uint xmod3 = dt.x % 3;\n"
|
||||
" float4 color1 = xmod3 <= 1 ? color0 : color3;\n"
|
||||
" float4 color2 = xmod3 == 0 ? color0 : color3;\n"
|
||||
" float b = color0.bgr[xmod3];\n"
|
||||
" float g = color1.grb[xmod3];\n"
|
||||
" float r = color2.rbg[xmod3];\n"
|
||||
" float a = color3.bgr[xmod3];\n"
|
||||
" dst[dt.xy] = float4(r, g, b, a);\n"
|
||||
"}\n";
|
||||
|
||||
return InitCompute(device, ranges, ARRAYSIZE(ranges), nullptr, 0, shader);
|
||||
}
|
||||
|
||||
PostProcessStatus CRGB24Effect::SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||
{
|
||||
if (src.desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM)
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
|
||||
const unsigned packedPitch = AlignTo((unsigned)src.desc.Width * 3, 4u);
|
||||
D3D12_RESOURCE_DESC desc = src.desc;
|
||||
desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
desc.Width = AlignTo(packedPitch / 4, 64u);
|
||||
desc.Height = ((unsigned)src.desc.Width * src.desc.Height) / (packedPitch / 3);
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
|
||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
||||
return PostProcessStatus::FAILED;
|
||||
|
||||
m_threadsX = ((unsigned)desc.Width + (Threads - 1)) / Threads;
|
||||
m_threadsY = ((unsigned)desc.Height + (Threads - 1)) / Threads;
|
||||
|
||||
dst.desc = desc;
|
||||
dst.format = FRAME_TYPE_BGR_32;
|
||||
return PostProcessStatus::SUCCESS;
|
||||
}
|
||||
|
||||
ComPtr<ID3D12Resource> CRGB24Effect::Run(const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
m_descHeap->GetCPUDescriptorHandleForHeapStart();
|
||||
const UINT inc = device->GetDescriptorHandleIncrementSize(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
|
||||
|
||||
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
device->CreateShaderResourceView(src.Get(), &srvDesc, handle);
|
||||
handle.ptr += inc;
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
device->CreateUnorderedAccessView(m_dst.Get(), nullptr, &uavDesc, handle);
|
||||
|
||||
Bind(commandList);
|
||||
commandList->Dispatch(m_threadsX, m_threadsY, 1);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
|
||||
for (RECT * rect = dirtyRects; rect < dirtyRects + *nbDirtyRects; ++rect)
|
||||
{
|
||||
unsigned width = rect->right - rect->left;
|
||||
rect->left = (rect->left * 3) / 4;
|
||||
rect->right = rect->left + (width * 3 + 3) / 4;
|
||||
}
|
||||
|
||||
return m_dst;
|
||||
}
|
||||
30
idd/LGIdd/effect/CRGB24Effect.h
Normal file
30
idd/LGIdd/effect/CRGB24Effect.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Looking Glass
|
||||
* Copyright © 2017-2026 The Looking Glass Authors
|
||||
* https://looking-glass.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CComputeEffect.h"
|
||||
|
||||
class CRGB24Effect : public CComputeEffect
|
||||
{
|
||||
public:
|
||||
const char * GetName() const override { return "RGB24"; }
|
||||
|
||||
bool Init(const ComPtr<ID3D12Device3>& device);
|
||||
|
||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||
|
||||
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||
unsigned * nbDirtyRects) override;
|
||||
};
|
||||
Reference in New Issue
Block a user