mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-04 06:12:04 +00:00
[idd] select linear RGB24 packing automatically
Replace the texture-shaped RGB24 output with a linear raw buffer and keep its packing, damage translation, and buffer copies inside the RGB24 effect. Benchmark full-frame native and packed processing and retain the faster path for each source format. Preserve logical damage rectangles for client updates and alternating framebuffer repair. Return compute outputs to COMMON for COPY queue handoff and refresh cached framebuffer sizes when switching packed and native layouts.
This commit is contained in:
@@ -41,13 +41,9 @@ CFrameBufferResource * CFrameBufferPool::Get(
|
||||
if (buffer.frameIndex > ARRAYSIZE(m_buffers) - 1)
|
||||
return nullptr;
|
||||
|
||||
CFrameBufferResource* fbr = &m_buffers[buffer.frameIndex];
|
||||
if (!fbr->IsValid() || fbr->GetBase() != buffer.mem || fbr->GetSize() < minSize)
|
||||
{
|
||||
fbr->Reset();
|
||||
CFrameBufferResource * fbr = &m_buffers[buffer.frameIndex];
|
||||
if (!fbr->Init(m_swapChain, buffer.frameIndex, buffer.mem, minSize))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return fbr;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ bool CFrameBufferResource::Init(CSwapChainProcessor * swapChain, unsigned frameI
|
||||
|
||||
if (size > swapChain->GetDevice()->GetMaxFrameSize())
|
||||
{
|
||||
DEBUG_ERROR("Frame size of %lu is too large to fit in available shared ram");
|
||||
DEBUG_ERROR("Frame size of %llu is too large to fit in shared ram",
|
||||
(unsigned long long)size);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -97,7 +98,7 @@ bool CFrameBufferResource::Init(CSwapChainProcessor * swapChain, unsigned frameI
|
||||
swapChain->GetD3D12Device()->GetHeap().Get(),
|
||||
(uintptr_t)base - (uintptr_t)swapChain->GetDevice()->GetIVSHMEM().GetMem(),
|
||||
&desc,
|
||||
D3D12_RESOURCE_STATE_COPY_DEST,
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
NULL,
|
||||
IID_PPV_ARGS(&m_res)
|
||||
);
|
||||
@@ -115,7 +116,6 @@ bool CFrameBufferResource::Init(CSwapChainProcessor * swapChain, unsigned frameI
|
||||
m_base = base;
|
||||
m_size = size;
|
||||
m_frameSize = size;
|
||||
m_valid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -131,5 +131,4 @@ void CFrameBufferResource::Reset()
|
||||
m_size = 0;
|
||||
m_frameSize = 0;
|
||||
m_res.Reset();
|
||||
m_valid = false;
|
||||
}
|
||||
@@ -33,7 +33,6 @@ using namespace Microsoft::WRL;
|
||||
class CFrameBufferResource
|
||||
{
|
||||
private:
|
||||
bool m_valid = false;
|
||||
unsigned m_frameIndex = 0;
|
||||
uint8_t * m_base = nullptr;
|
||||
size_t m_size = 0;
|
||||
@@ -41,6 +40,9 @@ class CFrameBufferResource
|
||||
uint64_t m_captureTime = 0;
|
||||
uint64_t m_postProcessStart = 0;
|
||||
uint64_t m_copyStart = 0;
|
||||
unsigned m_timingEffectIndex = 0;
|
||||
uint64_t m_timingToken = 0;
|
||||
bool m_fullCopy = false;
|
||||
ComPtr<ID3D12Resource> m_res;
|
||||
void * m_map = nullptr;
|
||||
|
||||
@@ -48,10 +50,7 @@ class CFrameBufferResource
|
||||
bool Init(CSwapChainProcessor * swapChain, unsigned frameIndex, uint8_t * base, size_t size);
|
||||
void Reset();
|
||||
|
||||
bool IsValid() { return m_valid; }
|
||||
unsigned GetFrameIndex() { return m_frameIndex; }
|
||||
uint8_t * GetBase() { return m_base; }
|
||||
size_t GetSize() { return m_size; }
|
||||
size_t GetFrameSize() { return m_frameSize; }
|
||||
void * GetMap() { return m_map; }
|
||||
|
||||
@@ -66,5 +65,16 @@ class CFrameBufferResource
|
||||
uint64_t GetPostProcessStart() const { return m_postProcessStart; }
|
||||
uint64_t GetCopyStart () const { return m_copyStart; }
|
||||
|
||||
void SetPostProcessSample(
|
||||
unsigned effectIndex, uint64_t token, bool fullCopy)
|
||||
{
|
||||
m_timingEffectIndex = effectIndex;
|
||||
m_timingToken = token;
|
||||
m_fullCopy = fullCopy;
|
||||
}
|
||||
unsigned GetTimingEffectIndex() const { return m_timingEffectIndex; }
|
||||
uint64_t GetTimingToken () const { return m_timingToken; }
|
||||
bool IsFullCopy () const { return m_fullCopy; }
|
||||
|
||||
ComPtr<ID3D12Resource> Get() { return m_res; }
|
||||
};
|
||||
|
||||
@@ -1249,6 +1249,11 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
{
|
||||
PreparedFrameBuffer result = {};
|
||||
|
||||
const unsigned dataWidth = dstFormat.dataWidth ?
|
||||
dstFormat.dataWidth : (unsigned)dstFormat.desc.Width;
|
||||
const unsigned dataHeight = dstFormat.dataHeight ?
|
||||
dstFormat.dataHeight : dstFormat.desc.Height;
|
||||
|
||||
if (!FrameBufferAvailable())
|
||||
return result;
|
||||
|
||||
@@ -1268,17 +1273,21 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
expected, true, std::memory_order_acq_rel))
|
||||
return result;
|
||||
|
||||
if (m_width != dstFormat.desc.Width ||
|
||||
m_height != dstFormat.desc.Height ||
|
||||
if (m_width != dataWidth ||
|
||||
m_height != dataHeight ||
|
||||
m_frameWidth != dstFormat.width ||
|
||||
m_frameHeight != dstFormat.height ||
|
||||
m_pitch != pitch ||
|
||||
m_format != dstFormat.desc.Format ||
|
||||
m_frameType != dstFormat.format)
|
||||
{
|
||||
m_width = (unsigned)dstFormat.desc.Width;
|
||||
m_height = dstFormat.desc.Height;
|
||||
m_width = dataWidth;
|
||||
m_height = dataHeight;
|
||||
m_frameWidth = dstFormat.width;
|
||||
m_frameHeight = dstFormat.height;
|
||||
m_pitch = pitch;
|
||||
m_format = dstFormat.desc.Format;
|
||||
m_frameType = dstFormat.format;
|
||||
m_pitch = pitch;
|
||||
++m_formatVer;
|
||||
}
|
||||
|
||||
@@ -1326,15 +1335,15 @@ CIndirectDeviceContext::PreparedFrameBuffer CIndirectDeviceContext::PrepareFrame
|
||||
(dstFormat.hdrPQ ? FRAME_FLAG_HDR_PQ : 0) |
|
||||
(dstFormat.hdrMetadata ? FRAME_FLAG_HDR_METADATA : 0);
|
||||
|
||||
if (maxRows < dstFormat.desc.Height)
|
||||
if (maxRows < dataHeight)
|
||||
flags |= FRAME_FLAG_TRUNCATED;
|
||||
|
||||
fi->formatVer = m_formatVer;
|
||||
fi->frameSerial = m_frameSerial++;
|
||||
fi->screenWidth = srcFormat.width;
|
||||
fi->screenHeight = srcFormat.height;
|
||||
fi->dataWidth = (unsigned)dstFormat.desc.Width;
|
||||
fi->dataHeight = min(maxRows, dstFormat.desc.Height);
|
||||
fi->dataWidth = dataWidth;
|
||||
fi->dataHeight = min(maxRows, dataHeight);
|
||||
fi->frameWidth = dstFormat.width;
|
||||
fi->frameHeight = dstFormat.height;
|
||||
fi->stride = pitch / bpp;
|
||||
|
||||
@@ -115,9 +115,12 @@ private:
|
||||
|
||||
unsigned m_width = 0;
|
||||
unsigned m_height = 0;
|
||||
unsigned m_frameWidth = 0;
|
||||
unsigned m_frameHeight = 0;
|
||||
unsigned m_pitch = 0;
|
||||
DXGI_FORMAT m_format = DXGI_FORMAT_UNKNOWN;
|
||||
FrameType m_frameType = FRAME_TYPE_INVALID;
|
||||
|
||||
UINT m_iddCxVersion = 0;
|
||||
bool m_hasIddCx110DDIs = false;
|
||||
bool m_canProcessFP16 = false;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "effect/CRGB24Effect.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
@@ -82,12 +83,16 @@ static void CopyHDRMetadata(D12FrameFormat& dst, const D12FrameFormat& src)
|
||||
dst.maxFrameAverageLightLevel = src.maxFrameAverageLightLevel;
|
||||
}
|
||||
|
||||
bool CPostProcessor::Init(std::shared_ptr<CD3D12Device> dx12Device)
|
||||
bool CPostProcessor::Init(std::shared_ptr<CD3D12Device> dx12Device,
|
||||
bool enableEffects)
|
||||
{
|
||||
m_dx12Device = dx12Device;
|
||||
m_device = dx12Device->GetDevice();
|
||||
m_effects.clear();
|
||||
|
||||
if (!enableEffects)
|
||||
return true;
|
||||
|
||||
std::unique_ptr<CColorTransformEffect> colorTransform(new CColorTransformEffect());
|
||||
if (colorTransform->Init(m_device))
|
||||
{
|
||||
@@ -130,6 +135,10 @@ void CPostProcessor::Reset()
|
||||
m_device.Reset();
|
||||
m_srcFormat = {};
|
||||
m_dstFormat = {};
|
||||
m_copyLayout = {};
|
||||
m_copyEffect = nullptr;
|
||||
m_frameSize = 0;
|
||||
m_pitch = 0;
|
||||
m_effectsActive = false;
|
||||
m_configured = false;
|
||||
}
|
||||
@@ -147,9 +156,26 @@ bool CPostProcessor::HasSameEffectChain(const CPostProcessor& other) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CPostProcessor::ShareEffectState(const CPostProcessor& other)
|
||||
{
|
||||
if (!HasSameEffectChain(other))
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < m_effects.size(); ++i)
|
||||
m_effects[i]->ShareState(*other.m_effects[i]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPostProcessor::Update(const D12FrameFormat& srcFormat)
|
||||
{
|
||||
for (const auto& effect : m_effects)
|
||||
effect->Update(srcFormat);
|
||||
}
|
||||
|
||||
bool CPostProcessor::NeedsReconfigure(const D12FrameFormat& srcFormat) const
|
||||
{
|
||||
return !m_configured ||
|
||||
if (!m_configured ||
|
||||
srcFormat.desc.Width != m_srcFormat.desc.Width ||
|
||||
srcFormat.desc.Height != m_srcFormat.desc.Height ||
|
||||
srcFormat.desc.Format != m_srcFormat.desc.Format ||
|
||||
@@ -158,7 +184,23 @@ bool CPostProcessor::NeedsReconfigure(const D12FrameFormat& srcFormat) const
|
||||
srcFormat.height != m_srcFormat.height ||
|
||||
srcFormat.hdr != m_srcFormat.hdr ||
|
||||
srcFormat.hdrPQ != m_srcFormat.hdrPQ ||
|
||||
srcFormat.colorTransform != m_srcFormat.colorTransform;
|
||||
srcFormat.colorTransform != m_srcFormat.colorTransform)
|
||||
return true;
|
||||
|
||||
for (const auto& effect : m_effects)
|
||||
if (effect->NeedsReconfigure())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPostProcessor::RequiresFullDamage() const
|
||||
{
|
||||
for (const auto& effect : m_effects)
|
||||
if (effect->RequiresFullDamage())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
@@ -170,7 +212,7 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
if (!NeedsReconfigure(srcFormat))
|
||||
{
|
||||
// Static HDR metadata may change independently of the resource format.
|
||||
// Propagate it without recreating textures or post-processing state.
|
||||
// Propagate it without recreating resources or post-processing state.
|
||||
CopyHDRMetadata(m_srcFormat, srcFormat);
|
||||
CopyHDRMetadata(m_dstFormat, srcFormat);
|
||||
return true;
|
||||
@@ -178,6 +220,7 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
|
||||
D12FrameFormat oldDst = m_dstFormat;
|
||||
D12FrameFormat cur = srcFormat;
|
||||
CPostProcessEffect * outputEffect = nullptr;
|
||||
bool effectsActive = false;
|
||||
|
||||
for (const auto& effect : m_effects)
|
||||
@@ -189,6 +232,7 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
effect->Enabled = true;
|
||||
effectsActive = true;
|
||||
cur = dst;
|
||||
outputEffect = effect.get();
|
||||
DEBUG_INFO("Post-processing effect active: %s", effect->GetName());
|
||||
break;
|
||||
|
||||
@@ -202,8 +246,53 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT copyLayout = {};
|
||||
CPostProcessEffect * copyEffect = nullptr;
|
||||
unsigned pitch = 0;
|
||||
unsigned dataHeight = 0;
|
||||
if (outputEffect && outputEffect->GetCopyLayout(&pitch, &dataHeight))
|
||||
copyEffect = outputEffect;
|
||||
else
|
||||
{
|
||||
if (cur.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
|
||||
{
|
||||
DEBUG_ERROR("Post-processing output has no copy implementation");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_device->GetCopyableFootprints(
|
||||
&cur.desc,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
©Layout,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
pitch = copyLayout.Footprint.RowPitch;
|
||||
dataHeight = cur.desc.Height;
|
||||
}
|
||||
|
||||
if (!pitch || !dataHeight ||
|
||||
pitch > (std::numeric_limits<size_t>::max)() / dataHeight)
|
||||
{
|
||||
DEBUG_ERROR("Invalid post-processing output layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t frameSize = (size_t)pitch * dataHeight;
|
||||
if (copyEffect && cur.desc.Width < frameSize)
|
||||
{
|
||||
DEBUG_ERROR("Post-processing output buffer is too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_srcFormat = srcFormat;
|
||||
m_dstFormat = cur;
|
||||
m_copyLayout = copyLayout;
|
||||
m_copyEffect = copyEffect;
|
||||
m_frameSize = frameSize;
|
||||
m_pitch = pitch;
|
||||
m_effectsActive = effectsActive;
|
||||
m_configured = true;
|
||||
if (formatChanged)
|
||||
@@ -211,6 +300,9 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
oldDst.desc.Width != m_dstFormat.desc.Width ||
|
||||
oldDst.desc.Height != m_dstFormat.desc.Height ||
|
||||
oldDst.desc.Format != m_dstFormat.desc.Format ||
|
||||
oldDst.dataWidth != m_dstFormat.dataWidth ||
|
||||
oldDst.dataHeight != m_dstFormat.dataHeight ||
|
||||
oldDst.pitch != m_dstFormat.pitch ||
|
||||
oldDst.format != m_dstFormat.format ||
|
||||
oldDst.width != m_dstFormat.width ||
|
||||
oldDst.height != m_dstFormat.height ||
|
||||
@@ -221,6 +313,89 @@ bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
|
||||
return true;
|
||||
}
|
||||
|
||||
void CPostProcessor::GetTimingToken(
|
||||
unsigned * effectIndex, uint64_t * token) const
|
||||
{
|
||||
if (effectIndex)
|
||||
*effectIndex = 0;
|
||||
if (token)
|
||||
*token = 0;
|
||||
|
||||
for (size_t i = 0; i < m_effects.size(); ++i)
|
||||
{
|
||||
const uint64_t value = m_effects[i]->GetTimingToken();
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
if (effectIndex)
|
||||
*effectIndex = (unsigned)i;
|
||||
if (token)
|
||||
*token = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CPostProcessor::RecordTiming(
|
||||
unsigned effectIndex, uint64_t token, bool fullCopy, uint64_t totalTime)
|
||||
{
|
||||
if (!token || effectIndex >= m_effects.size())
|
||||
return;
|
||||
|
||||
m_effects[effectIndex]->RecordTiming(token, fullCopy, totalTime);
|
||||
}
|
||||
|
||||
bool CPostProcessor::ShouldCopyFully(
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects) const
|
||||
{
|
||||
return m_copyEffect &&
|
||||
m_copyEffect->ShouldCopyFully(dirtyRects, nbDirtyRects);
|
||||
}
|
||||
|
||||
void CPostProcessor::CopyFrame(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
ID3D12Resource * dst, ID3D12Resource * src,
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
|
||||
{
|
||||
if (m_copyEffect)
|
||||
{
|
||||
m_copyEffect->CopyFrame(
|
||||
commandList, dst, src, dirtyRects, nbDirtyRects, fullCopy);
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
|
||||
srcLoc.pResource = src;
|
||||
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
srcLoc.SubresourceIndex = 0;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
|
||||
dstLoc.pResource = dst;
|
||||
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dstLoc.PlacedFootprint = m_copyLayout;
|
||||
|
||||
if (fullCopy)
|
||||
{
|
||||
commandList->CopyTextureRegion(
|
||||
&dstLoc, 0, 0, 0, &srcLoc, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const RECT * rect = dirtyRects;
|
||||
rect < dirtyRects + nbDirtyRects; ++rect)
|
||||
{
|
||||
D3D12_BOX box = {};
|
||||
box.left = rect->left;
|
||||
box.top = rect->top;
|
||||
box.front = 0;
|
||||
box.right = rect->right;
|
||||
box.bottom = rect->bottom;
|
||||
box.back = 1;
|
||||
|
||||
commandList->CopyTextureRegion(
|
||||
&dstLoc, box.left, box.top, 0, &srcLoc, &box);
|
||||
}
|
||||
}
|
||||
|
||||
void CPostProcessor::AdjustFrameDamage(RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||
{
|
||||
for (const auto& effect : m_effects)
|
||||
|
||||
@@ -56,6 +56,9 @@ bool IsIdentityColorTransform(const D12ColorTransform& transform);
|
||||
struct D12FrameFormat
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
unsigned dataWidth = 0;
|
||||
unsigned dataHeight = 0;
|
||||
unsigned pitch = 0;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
FrameType format = FRAME_TYPE_INVALID;
|
||||
@@ -84,6 +87,51 @@ class CPostProcessEffect
|
||||
public:
|
||||
virtual ~CPostProcessEffect() {}
|
||||
virtual const char * GetName() const = 0;
|
||||
virtual void ShareState(const CPostProcessEffect& other)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(other);
|
||||
}
|
||||
virtual void Update(const D12FrameFormat& format)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(format);
|
||||
}
|
||||
virtual bool NeedsReconfigure() const { return false; }
|
||||
virtual bool RequiresFullDamage() const { return false; }
|
||||
virtual uint64_t GetTimingToken() const { return 0; }
|
||||
virtual void RecordTiming(
|
||||
uint64_t token, bool fullCopy, uint64_t totalTime)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(token);
|
||||
UNREFERENCED_PARAMETER(fullCopy);
|
||||
UNREFERENCED_PARAMETER(totalTime);
|
||||
}
|
||||
// A final effect with a non-texture output owns its framebuffer copy.
|
||||
virtual bool GetCopyLayout(
|
||||
unsigned * pitch, unsigned * dataHeight) const
|
||||
{
|
||||
UNREFERENCED_PARAMETER(pitch);
|
||||
UNREFERENCED_PARAMETER(dataHeight);
|
||||
return false;
|
||||
}
|
||||
virtual bool ShouldCopyFully(
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects) const
|
||||
{
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
return false;
|
||||
}
|
||||
virtual void CopyFrame(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
ID3D12Resource * dst, ID3D12Resource * src,
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
|
||||
{
|
||||
UNREFERENCED_PARAMETER(commandList);
|
||||
UNREFERENCED_PARAMETER(dst);
|
||||
UNREFERENCED_PARAMETER(src);
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
UNREFERENCED_PARAMETER(fullCopy);
|
||||
}
|
||||
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); }
|
||||
@@ -102,15 +150,23 @@ private:
|
||||
std::vector<std::unique_ptr<CPostProcessEffect>> m_effects;
|
||||
D12FrameFormat m_srcFormat = {};
|
||||
D12FrameFormat m_dstFormat = {};
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT m_copyLayout = {};
|
||||
CPostProcessEffect * m_copyEffect = nullptr;
|
||||
size_t m_frameSize = 0;
|
||||
unsigned m_pitch = 0;
|
||||
bool m_effectsActive = false;
|
||||
bool m_configured = false;
|
||||
|
||||
public:
|
||||
bool Init(std::shared_ptr<CD3D12Device> dx12Device);
|
||||
bool Init(std::shared_ptr<CD3D12Device> dx12Device,
|
||||
bool enableEffects);
|
||||
void Reset();
|
||||
|
||||
bool HasSameEffectChain(const CPostProcessor& other) const;
|
||||
bool ShareEffectState(const CPostProcessor& other);
|
||||
void Update(const D12FrameFormat& srcFormat);
|
||||
bool NeedsReconfigure(const D12FrameFormat& srcFormat) const;
|
||||
bool RequiresFullDamage() const;
|
||||
bool Configure(const D12FrameFormat& srcFormat, bool * formatChanged);
|
||||
void AdjustFrameDamage(RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||
ComPtr<ID3D12Resource> Run(
|
||||
@@ -120,4 +176,15 @@ public:
|
||||
|
||||
const D12FrameFormat& GetOutputFormat() const { return m_dstFormat; }
|
||||
bool HasActiveEffects() const { return m_effectsActive; }
|
||||
void GetTimingToken(unsigned * effectIndex, uint64_t * token) const;
|
||||
void RecordTiming(unsigned effectIndex, uint64_t token,
|
||||
bool fullCopy, uint64_t totalTime);
|
||||
unsigned GetOutputPitch() const { return m_pitch; }
|
||||
size_t GetOutputSize () const { return m_frameSize; }
|
||||
bool ShouldCopyFully(
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects) const;
|
||||
void CopyFrame(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
ID3D12Resource * dst, ID3D12Resource * src,
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const;
|
||||
};
|
||||
|
||||
@@ -79,13 +79,13 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex
|
||||
{
|
||||
m_resPool.Init(dx11Device, dx12Device);
|
||||
m_fbPool.Init(this);
|
||||
if (m_dx11Device->IsSoftware())
|
||||
const bool enableEffects = !m_dx11Device->IsSoftware();
|
||||
if (!enableEffects)
|
||||
DEBUG_INFO("Software render adapter: post-processing disabled");
|
||||
else
|
||||
{
|
||||
|
||||
bool initialized = true;
|
||||
for (CPostProcessor& postProcessor : m_postProcessors)
|
||||
if (!postProcessor.Init(dx12Device))
|
||||
if (!postProcessor.Init(dx12Device, enableEffects))
|
||||
{
|
||||
initialized = false;
|
||||
break;
|
||||
@@ -93,7 +93,7 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex
|
||||
|
||||
if (initialized)
|
||||
for (unsigned i = 1; i < ARRAYSIZE(m_postProcessors); ++i)
|
||||
if (!m_postProcessors[0].HasSameEffectChain(m_postProcessors[i]))
|
||||
if (!m_postProcessors[i].ShareEffectState(m_postProcessors[0]))
|
||||
{
|
||||
DEBUG_ERROR("Post processor effect chains do not match");
|
||||
initialized = false;
|
||||
@@ -103,9 +103,13 @@ CSwapChainProcessor::CSwapChainProcessor(CIndirectMonitorContext * monitorContex
|
||||
if (!initialized)
|
||||
{
|
||||
for (CPostProcessor& postProcessor : m_postProcessors)
|
||||
{
|
||||
postProcessor.Reset();
|
||||
DEBUG_ERROR("Failed to initialize post processors");
|
||||
if (!postProcessor.Init(dx12Device, false))
|
||||
DEBUG_ERROR("Failed to initialize post processor copy support");
|
||||
}
|
||||
DEBUG_WARN(
|
||||
"Failed to initialize post-processing effects; effects disabled");
|
||||
}
|
||||
|
||||
// Manual-reset: both worker threads wait on this, so it must stay signalled
|
||||
@@ -363,7 +367,7 @@ void CSwapChainProcessor::CompletionFunction(
|
||||
fbRes->GetFrameIndex(), fbRes->GetMap(), 0, fbRes->GetFrameSize(), false);
|
||||
|
||||
// Queue waits execute before the start timestamp. The end timestamp follows
|
||||
// the last CopyTextureRegion, separating GPU work from readiness dispatch.
|
||||
// the last copy command, separating GPU work from readiness dispatch.
|
||||
const bool gpuTimingValid =
|
||||
slot->GetGPUTimes(gpuCopyStart, gpuCopyEnd);
|
||||
|
||||
@@ -384,6 +388,9 @@ void CSwapChainProcessor::CompletionFunction(
|
||||
readyTime = readyEnd - gpuCopyEnd;
|
||||
}
|
||||
|
||||
sc->m_postProcessors[fbRes->GetFrameIndex()].RecordTiming(
|
||||
fbRes->GetTimingEffectIndex(), fbRes->GetTimingToken(),
|
||||
fbRes->IsFullCopy(), postProcessTime + copyTime + readyTime);
|
||||
sc->m_devContext->SetFrameTiming(fbRes->GetFrameIndex(),
|
||||
fbRes->GetCaptureTime(), postProcessTime, copyTime, readyTime);
|
||||
sc->m_devContext->CompleteFrameBuffer(fbRes->GetFrameIndex());
|
||||
@@ -391,14 +398,14 @@ void CSwapChainProcessor::CompletionFunction(
|
||||
|
||||
|
||||
static bool IsFullDamage(const RECT * dirtyRects, unsigned nbDirtyRects,
|
||||
const D3D12_RESOURCE_DESC& desc)
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
for (const RECT * rect = dirtyRects;
|
||||
rect < dirtyRects + nbDirtyRects; ++rect)
|
||||
if (rect->left == 0 &&
|
||||
rect->top == 0 &&
|
||||
rect->right == (LONG)desc.Width &&
|
||||
rect->bottom == (LONG)desc.Height)
|
||||
rect->right == (LONG)width &&
|
||||
rect->bottom == (LONG)height)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -470,9 +477,9 @@ static bool AddCopyDirtyRect(RECT dirtyRects[], unsigned capacity,
|
||||
}
|
||||
|
||||
static bool CopyAreaCoversFrame(const RECT * dirtyRects,
|
||||
unsigned nbDirtyRects, const D3D12_RESOURCE_DESC& desc)
|
||||
unsigned nbDirtyRects, unsigned width, unsigned height)
|
||||
{
|
||||
const uint64_t frameArea = (uint64_t)desc.Width * desc.Height;
|
||||
const uint64_t frameArea = (uint64_t)width * height;
|
||||
uint64_t copyArea = 0;
|
||||
|
||||
for (const RECT * rect = dirtyRects;
|
||||
@@ -487,26 +494,10 @@ static bool CopyAreaCoversFrame(const RECT * dirtyRects,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void CopyDirtyRect(ComPtr<ID3D12GraphicsCommandList> list,
|
||||
D3D12_TEXTURE_COPY_LOCATION * dstLoc,
|
||||
D3D12_TEXTURE_COPY_LOCATION * srcLoc,
|
||||
const RECT& rect)
|
||||
static bool ClipDirtyRect(RECT& rect, unsigned width, unsigned height)
|
||||
{
|
||||
D3D12_BOX box = {};
|
||||
box.left = rect.left;
|
||||
box.top = rect.top;
|
||||
box.front = 0;
|
||||
box.right = rect.right;
|
||||
box.bottom = rect.bottom;
|
||||
box.back = 1;
|
||||
|
||||
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;
|
||||
const LONG maxRight = (LONG)width;
|
||||
const LONG maxBottom = (LONG)height;
|
||||
|
||||
if (rect.left < 0 ) rect.left = 0;
|
||||
if (rect.top < 0 ) rect.top = 0;
|
||||
@@ -517,13 +508,13 @@ static bool ClipDirtyRect(RECT& rect, const D3D12_RESOURCE_DESC& desc)
|
||||
}
|
||||
|
||||
static void ClipDirtyRects(RECT dirtyRects[], unsigned * nbDirtyRects,
|
||||
const D3D12_RESOURCE_DESC& desc)
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
unsigned out = 0;
|
||||
for (unsigned i = 0; i < *nbDirtyRects; ++i)
|
||||
{
|
||||
RECT rect = dirtyRects[i];
|
||||
if (ClipDirtyRect(rect, desc))
|
||||
if (ClipDirtyRect(rect, width, height))
|
||||
dirtyRects[out++] = rect;
|
||||
}
|
||||
*nbDirtyRects = out;
|
||||
@@ -816,6 +807,8 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
break;
|
||||
}
|
||||
|
||||
m_postProcessors[0].Update(srcFormat);
|
||||
|
||||
const bool frameMetadataChanged = noImageUpdate &&
|
||||
FrameMetadataChanged(m_postProcessors[0].GetOutputFormat(), srcFormat);
|
||||
|
||||
@@ -836,7 +829,13 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
m_dx12Device->WaitForIdle();
|
||||
}
|
||||
|
||||
// An optional adaptive effect can reject its candidate while configuring
|
||||
// either slot. Both queues are already idle, so allow one convergence pass
|
||||
// to return both effect chains to the same mode.
|
||||
bool postProcessFormatChanged = false;
|
||||
bool configurationStable = false;
|
||||
for (unsigned pass = 0; pass < 2 && !configurationStable; ++pass)
|
||||
{
|
||||
for (unsigned i = 0; i < ARRAYSIZE(m_postProcessors); ++i)
|
||||
{
|
||||
bool formatChanged = false;
|
||||
@@ -847,7 +846,23 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
postProcessFormatChanged = formatChanged;
|
||||
postProcessFormatChanged |= formatChanged;
|
||||
}
|
||||
|
||||
configurationStable = true;
|
||||
for (const CPostProcessor& postProcessor : m_postProcessors)
|
||||
if (postProcessor.NeedsReconfigure(srcFormat))
|
||||
{
|
||||
configurationStable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!configurationStable)
|
||||
{
|
||||
DEBUG_ERROR("Post processor configuration did not stabilize");
|
||||
SetFullPendingDamage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (postProcessFormatChanged)
|
||||
@@ -858,37 +873,34 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
else if (frameMetadataChanged)
|
||||
SetFullPendingDamage();
|
||||
|
||||
// Adaptive effects need comparable full-frame samples until they lock.
|
||||
if (m_postProcessors[0].RequiresFullDamage())
|
||||
SetFullPendingDamage();
|
||||
|
||||
if (noImageUpdate && !m_hasPendingDamage)
|
||||
return true;
|
||||
|
||||
const D12FrameFormat& dstFormat =
|
||||
m_postProcessors[0].GetOutputFormat();
|
||||
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
|
||||
m_dx12Device->GetDevice()->GetCopyableFootprints(
|
||||
&dstFormat.desc,
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
&layout,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
const unsigned pitch = m_postProcessors[0].GetOutputPitch();
|
||||
const size_t frameSize = m_postProcessors[0].GetOutputSize();
|
||||
|
||||
RECT currentDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||
RECT frameDirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||
unsigned nbDirtyRects = m_nbPendingDirtyRects;
|
||||
unsigned frameDirtyRectCount = nbDirtyRects;
|
||||
if (nbDirtyRects)
|
||||
{
|
||||
memcpy(currentDirtyRects, m_pendingDirtyRects, nbDirtyRects * sizeof(*currentDirtyRects));
|
||||
memcpy(frameDirtyRects, currentDirtyRects, nbDirtyRects * sizeof(*frameDirtyRects));
|
||||
memcpy(currentDirtyRects, m_pendingDirtyRects,
|
||||
nbDirtyRects * sizeof(*currentDirtyRects));
|
||||
memcpy(frameDirtyRects, currentDirtyRects,
|
||||
nbDirtyRects * sizeof(*frameDirtyRects));
|
||||
}
|
||||
unsigned frameDirtyRectCount = nbDirtyRects;
|
||||
m_postProcessors[0].AdjustFrameDamage(
|
||||
frameDirtyRects, &frameDirtyRectCount);
|
||||
|
||||
auto buffer = m_devContext->PrepareFrameBuffer(
|
||||
(unsigned)layout.Footprint.RowPitch,
|
||||
pitch,
|
||||
srcFormat,
|
||||
dstFormat,
|
||||
frameDirtyRects,
|
||||
@@ -899,8 +911,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
if (!buffer.mem)
|
||||
return true;
|
||||
|
||||
CFrameBufferResource * fbRes = m_fbPool.Get(buffer,
|
||||
(size_t)layout.Footprint.RowPitch * dstFormat.desc.Height);
|
||||
CFrameBufferResource * fbRes = m_fbPool.Get(buffer, frameSize);
|
||||
|
||||
if (!fbRes)
|
||||
{
|
||||
@@ -986,23 +997,14 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
return false;
|
||||
}
|
||||
|
||||
ClipDirtyRects(currentDirtyRects, &nbDirtyRects, dstFormat.desc);
|
||||
ClipDirtyRects(currentDirtyRects, &nbDirtyRects,
|
||||
dstFormat.width, dstFormat.height);
|
||||
|
||||
const uint64_t copyStart = Nanotime();
|
||||
fbRes->SetTiming(captureTime, postProcessStart, copyStart);
|
||||
|
||||
copySlot->SetCompletionCallback(&CompletionFunction, this, fbRes);
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
|
||||
srcLoc.pResource = copySrcResource.Get();
|
||||
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
srcLoc.SubresourceIndex = 0;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
|
||||
dstLoc.pResource = fbRes->Get().Get();
|
||||
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dstLoc.PlacedFootprint = layout;
|
||||
|
||||
/* Each destination is reused every other frame, so repair both the prior
|
||||
* and current damage. Coalesce them first to avoid copying overlapping
|
||||
* regions, especially a prior full frame, more than once. */
|
||||
@@ -1017,7 +1019,7 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
rect < m_dirtyRects + m_nbDirtyRects && !fullCopy; ++rect)
|
||||
{
|
||||
RECT clipped = *rect;
|
||||
if (ClipDirtyRect(clipped, dstFormat.desc) &&
|
||||
if (ClipDirtyRect(clipped, dstFormat.width, dstFormat.height) &&
|
||||
!AddCopyDirtyRect(copyDirtyRects, ARRAYSIZE(copyDirtyRects),
|
||||
&nbCopyDirtyRects, clipped))
|
||||
fullCopy = true;
|
||||
@@ -1031,25 +1033,29 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
||||
|
||||
if (!fullCopy)
|
||||
fullCopy = IsFullDamage(
|
||||
copyDirtyRects, nbCopyDirtyRects, dstFormat.desc) ||
|
||||
copyDirtyRects, nbCopyDirtyRects,
|
||||
dstFormat.width, dstFormat.height) ||
|
||||
CopyAreaCoversFrame(
|
||||
copyDirtyRects, nbCopyDirtyRects, dstFormat.desc);
|
||||
copyDirtyRects, nbCopyDirtyRects,
|
||||
dstFormat.width, dstFormat.height);
|
||||
|
||||
if (!fullCopy)
|
||||
fullCopy = postProcessor.ShouldCopyFully(
|
||||
copyDirtyRects, nbCopyDirtyRects);
|
||||
}
|
||||
|
||||
unsigned timingEffectIndex = 0;
|
||||
uint64_t timingToken = 0;
|
||||
postProcessor.GetTimingToken(&timingEffectIndex, &timingToken);
|
||||
fbRes->SetPostProcessSample(
|
||||
timingEffectIndex, timingToken, fullCopy);
|
||||
|
||||
// Source/compute waits are submitted immediately before this command list.
|
||||
// The timestamp therefore marks the first actual copy operation.
|
||||
copySlot->BeginTiming();
|
||||
if (fullCopy)
|
||||
{
|
||||
copySlot->GetGfxList()->CopyTextureRegion(
|
||||
&dstLoc, 0, 0, 0, &srcLoc, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const RECT * rect = copyDirtyRects;
|
||||
rect < copyDirtyRects + nbCopyDirtyRects; ++rect)
|
||||
CopyDirtyRect(copySlot->GetGfxList(), &dstLoc, &srcLoc, *rect);
|
||||
}
|
||||
postProcessor.CopyFrame(
|
||||
copySlot->GetGfxList(), fbRes->Get().Get(), copySrcResource.Get(),
|
||||
copyDirtyRects, nbCopyDirtyRects, fullCopy);
|
||||
copySlot->EndTiming();
|
||||
|
||||
if (!copySlot->Execute())
|
||||
|
||||
@@ -63,9 +63,9 @@ private:
|
||||
DWORD m_lastShapeId = 0;
|
||||
std::atomic<UINT> m_sdrWhiteLevel { KVMFR_SDR_WHITE_LEVEL_DEFAULT };
|
||||
|
||||
// Output-space damage from the previous published frame. The shared-memory
|
||||
// frame buffers alternate, so this must be copied along with the current
|
||||
// damage to bring the older target buffer up to date.
|
||||
// Logical output-space damage from the previous published frame. The
|
||||
// shared-memory frame buffers alternate, so this must be copied along with
|
||||
// the current damage to bring the older target buffer up to date.
|
||||
RECT m_dirtyRects[LG_MAX_DIRTY_RECTS] = {};
|
||||
unsigned m_nbDirtyRects = 0;
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ ComPtr<ID3D12Resource> CColorTransformEffect::Run(
|
||||
m_uploadPending = false;
|
||||
}
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
@@ -332,6 +332,6 @@ ComPtr<ID3D12Resource> CColorTransformEffect::Run(
|
||||
commandList->Dispatch(m_threadsX, m_threadsY, 1);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
D3D12_RESOURCE_STATE_COMMON);
|
||||
return m_dst;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
namespace PostProcessUtil
|
||||
{
|
||||
bool CreateDefaultTexture(const ComPtr<ID3D12Device3>& device,
|
||||
static bool CreateDefaultResource(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_RESOURCE_DESC& desc, ComPtr<ID3D12Resource>& resource)
|
||||
{
|
||||
D3D12_HEAP_PROPERTIES heapProps = {};
|
||||
@@ -41,17 +41,38 @@ namespace PostProcessUtil
|
||||
&heapProps,
|
||||
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED,
|
||||
&desc,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
nullptr,
|
||||
IID_PPV_ARGS(&resource));
|
||||
if (FAILED(hr))
|
||||
{
|
||||
DEBUG_ERROR_HR(hr, "Failed to create post-processing destination texture");
|
||||
DEBUG_ERROR_HR(hr, "Failed to create post-processing destination resource");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateDefaultTexture(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_RESOURCE_DESC& desc, ComPtr<ID3D12Resource>& resource)
|
||||
{
|
||||
return CreateDefaultResource(device, desc, resource);
|
||||
}
|
||||
|
||||
bool CreateDefaultBuffer(const ComPtr<ID3D12Device3>& device,
|
||||
UINT64 size, ComPtr<ID3D12Resource>& resource)
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
|
||||
desc.Width = size;
|
||||
desc.Height = 1;
|
||||
desc.DepthOrArraySize = 1;
|
||||
desc.MipLevels = 1;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
|
||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||
return CreateDefaultResource(device, desc, resource);
|
||||
}
|
||||
}
|
||||
|
||||
bool CComputeEffect::InitCompute(const ComPtr<ID3D12Device3>& device,
|
||||
|
||||
@@ -37,6 +37,8 @@ namespace PostProcessUtil
|
||||
|
||||
bool CreateDefaultTexture(const ComPtr<ID3D12Device3>& device,
|
||||
const D3D12_RESOURCE_DESC& desc, ComPtr<ID3D12Resource>& resource);
|
||||
bool CreateDefaultBuffer(const ComPtr<ID3D12Device3>& device,
|
||||
UINT64 size, ComPtr<ID3D12Resource>& resource);
|
||||
}
|
||||
|
||||
class CComputeEffect : public CPostProcessEffect
|
||||
|
||||
@@ -241,7 +241,7 @@ ComPtr<ID3D12Resource> CDownsampleEffect::Run(
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
@@ -273,6 +273,6 @@ ComPtr<ID3D12Resource> CDownsampleEffect::Run(
|
||||
commandList->Dispatch(m_threadsX, m_threadsY, 1);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
D3D12_RESOURCE_STATE_COMMON);
|
||||
return m_dst;
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ ComPtr<ID3D12Resource> CHDR16to10Effect::Run(
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
@@ -187,6 +187,6 @@ ComPtr<ID3D12Resource> CHDR16to10Effect::Run(
|
||||
commandList->Dispatch(m_threadsX, m_threadsY, 1);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||
D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
D3D12_RESOURCE_STATE_COMMON);
|
||||
return m_dst;
|
||||
}
|
||||
|
||||
@@ -20,13 +20,275 @@
|
||||
|
||||
#include "CRGB24Effect.h"
|
||||
|
||||
#include "CDebug.h"
|
||||
#include "../CSettings.h"
|
||||
#include "common/LGMPConfig.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <climits>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
using namespace PostProcessUtil;
|
||||
|
||||
static_assert(D3D12_TEXTURE_DATA_PITCH_ALIGNMENT == 256,
|
||||
"RGB24 shader row alignment must match D3D12");
|
||||
|
||||
struct CRGB24Effect::State
|
||||
{
|
||||
enum class Phase
|
||||
{
|
||||
DISABLED,
|
||||
NATIVE_WARMUP,
|
||||
NATIVE_SAMPLE,
|
||||
PACKED_WARMUP,
|
||||
PACKED_SAMPLE,
|
||||
LOCKED_NATIVE,
|
||||
LOCKED_PACKED,
|
||||
};
|
||||
|
||||
struct FormatKey
|
||||
{
|
||||
D3D12_RESOURCE_DIMENSION resourceDimension = D3D12_RESOURCE_DIMENSION_UNKNOWN;
|
||||
UINT64 resourceWidth = 0;
|
||||
UINT resourceHeight = 0;
|
||||
DXGI_FORMAT resourceFormat = DXGI_FORMAT_UNKNOWN;
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
FrameType format = FRAME_TYPE_INVALID;
|
||||
bool hdr = false;
|
||||
bool hdrPQ = false;
|
||||
std::shared_ptr<const D12ColorTransform> colorTransform;
|
||||
};
|
||||
|
||||
static const unsigned WarmupCount = LGMP_Q_FRAME_LEN;
|
||||
static const unsigned SampleCount = 64;
|
||||
static const unsigned TrimCount = SampleCount / 8;
|
||||
|
||||
SRWLOCK lock = SRWLOCK_INIT;
|
||||
Phase phase = Phase::DISABLED;
|
||||
FormatKey format = {};
|
||||
bool formatValid = false;
|
||||
uint64_t generation = 0;
|
||||
unsigned warmups = 0;
|
||||
unsigned sampleCount = 0;
|
||||
uint64_t nativeMean = 0;
|
||||
uint64_t samples[SampleCount] = {};
|
||||
|
||||
static bool IsEligible(const D12FrameFormat& format)
|
||||
{
|
||||
if (format.hdr ||
|
||||
format.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||
format.desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM)
|
||||
return false;
|
||||
|
||||
if (!format.colorTransform ||
|
||||
(!format.colorTransform->matrixEnabled &&
|
||||
!format.colorTransform->lutEnabled))
|
||||
return true;
|
||||
|
||||
return IsIdentityColorTransform(*format.colorTransform);
|
||||
}
|
||||
|
||||
bool WantsPackedLocked() const
|
||||
{
|
||||
return phase == Phase::PACKED_WARMUP ||
|
||||
phase == Phase::PACKED_SAMPLE ||
|
||||
phase == Phase::LOCKED_PACKED;
|
||||
}
|
||||
|
||||
bool IsBenchmarkingLocked() const
|
||||
{
|
||||
return phase == Phase::NATIVE_WARMUP ||
|
||||
phase == Phase::NATIVE_SAMPLE ||
|
||||
phase == Phase::PACKED_WARMUP ||
|
||||
phase == Phase::PACKED_SAMPLE;
|
||||
}
|
||||
|
||||
void ResetStageLocked()
|
||||
{
|
||||
warmups = 0;
|
||||
sampleCount = 0;
|
||||
std::memset(samples, 0, sizeof(samples));
|
||||
}
|
||||
|
||||
uint64_t TrimmedMeanLocked()
|
||||
{
|
||||
std::sort(samples, samples + SampleCount);
|
||||
|
||||
uint64_t total = 0;
|
||||
for (unsigned i = TrimCount; i < SampleCount - TrimCount; ++i)
|
||||
total += samples[i];
|
||||
|
||||
return total / (SampleCount - TrimCount * 2);
|
||||
}
|
||||
|
||||
void Update(const D12FrameFormat& next)
|
||||
{
|
||||
AcquireSRWLockExclusive(&lock);
|
||||
|
||||
const bool formatChanged = !formatValid ||
|
||||
format.resourceDimension != next.desc.Dimension ||
|
||||
format.resourceWidth != next.desc.Width ||
|
||||
format.resourceHeight != next.desc.Height ||
|
||||
format.resourceFormat != next.desc.Format ||
|
||||
format.width != next.width ||
|
||||
format.height != next.height ||
|
||||
format.format != next.format ||
|
||||
format.hdr != next.hdr ||
|
||||
format.hdrPQ != next.hdrPQ ||
|
||||
format.colorTransform != next.colorTransform;
|
||||
|
||||
if (formatChanged)
|
||||
{
|
||||
format.resourceDimension = next.desc.Dimension;
|
||||
format.resourceWidth = next.desc.Width;
|
||||
format.resourceHeight = next.desc.Height;
|
||||
format.resourceFormat = next.desc.Format;
|
||||
format.width = next.width;
|
||||
format.height = next.height;
|
||||
format.format = next.format;
|
||||
format.hdr = next.hdr;
|
||||
format.hdrPQ = next.hdrPQ;
|
||||
format.colorTransform = next.colorTransform;
|
||||
formatValid = true;
|
||||
|
||||
phase = IsEligible(next) ?
|
||||
Phase::NATIVE_WARMUP : Phase::DISABLED;
|
||||
nativeMean = 0;
|
||||
++generation;
|
||||
ResetStageLocked();
|
||||
}
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
case Phase::NATIVE_WARMUP:
|
||||
if (warmups >= WarmupCount)
|
||||
{
|
||||
phase = Phase::NATIVE_SAMPLE;
|
||||
++generation;
|
||||
ResetStageLocked();
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::NATIVE_SAMPLE:
|
||||
if (sampleCount >= SampleCount)
|
||||
{
|
||||
nativeMean = TrimmedMeanLocked();
|
||||
phase = Phase::PACKED_WARMUP;
|
||||
++generation;
|
||||
ResetStageLocked();
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::PACKED_WARMUP:
|
||||
if (warmups >= WarmupCount)
|
||||
{
|
||||
phase = Phase::PACKED_SAMPLE;
|
||||
++generation;
|
||||
ResetStageLocked();
|
||||
}
|
||||
break;
|
||||
|
||||
case Phase::PACKED_SAMPLE:
|
||||
if (sampleCount >= SampleCount)
|
||||
{
|
||||
const uint64_t packedMean = TrimmedMeanLocked();
|
||||
const uint64_t relativeThreshold = nativeMean / 20;
|
||||
const uint64_t threshold = relativeThreshold > 50000ULL ?
|
||||
relativeThreshold : 50000ULL;
|
||||
// Prefer the bandwidth saving unless native is meaningfully faster.
|
||||
const bool usePacked = packedMean <= nativeMean ||
|
||||
packedMean - nativeMean <= threshold;
|
||||
|
||||
DEBUG_INFO(
|
||||
"RGB24 benchmark: native=%llu us, packed=%llu us, selected=%s",
|
||||
(unsigned long long)(nativeMean / 1000),
|
||||
(unsigned long long)(packedMean / 1000),
|
||||
usePacked ? "packed" : "native");
|
||||
|
||||
phase = usePacked ?
|
||||
Phase::LOCKED_PACKED : Phase::LOCKED_NATIVE;
|
||||
++generation;
|
||||
ResetStageLocked();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive(&lock);
|
||||
}
|
||||
|
||||
bool WantsPacked()
|
||||
{
|
||||
AcquireSRWLockShared(&lock);
|
||||
const bool result = WantsPackedLocked();
|
||||
ReleaseSRWLockShared(&lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IsBenchmarking()
|
||||
{
|
||||
AcquireSRWLockShared(&lock);
|
||||
const bool result = IsBenchmarkingLocked();
|
||||
ReleaseSRWLockShared(&lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t GetTimingToken(bool packed)
|
||||
{
|
||||
AcquireSRWLockShared(&lock);
|
||||
|
||||
const uint64_t result = IsBenchmarkingLocked() &&
|
||||
packed == WantsPackedLocked() ? generation : 0;
|
||||
|
||||
ReleaseSRWLockShared(&lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Reject()
|
||||
{
|
||||
AcquireSRWLockExclusive(&lock);
|
||||
if (WantsPackedLocked())
|
||||
{
|
||||
phase = Phase::LOCKED_NATIVE;
|
||||
++generation;
|
||||
ResetStageLocked();
|
||||
}
|
||||
ReleaseSRWLockExclusive(&lock);
|
||||
}
|
||||
|
||||
void RecordTiming(uint64_t token, bool fullCopy, uint64_t totalTime)
|
||||
{
|
||||
AcquireSRWLockExclusive(&lock);
|
||||
|
||||
if (token == generation && fullCopy)
|
||||
switch (phase)
|
||||
{
|
||||
case Phase::NATIVE_WARMUP:
|
||||
case Phase::PACKED_WARMUP:
|
||||
++warmups;
|
||||
break;
|
||||
|
||||
case Phase::NATIVE_SAMPLE:
|
||||
case Phase::PACKED_SAMPLE:
|
||||
if (sampleCount < SampleCount)
|
||||
samples[sampleCount++] = totalTime;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseSRWLockExclusive(&lock);
|
||||
}
|
||||
};
|
||||
|
||||
bool CRGB24Effect::Init(const ComPtr<ID3D12Device3>& device)
|
||||
{
|
||||
if (!g_settings.ReadBoolValue(L"AllowRGB24", false))
|
||||
if (!g_settings.ReadBoolValue(L"AllowRGB24", true))
|
||||
return false;
|
||||
|
||||
D3D12_DESCRIPTOR_RANGE ranges[2] = {};
|
||||
@@ -40,48 +302,234 @@ bool CRGB24Effect::Init(const ComPtr<ID3D12Device3>& device)
|
||||
ranges[1].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
|
||||
|
||||
const char * shader =
|
||||
"Texture2D <float4> src : register(t0);\n"
|
||||
"RWTexture2D<float4> dst : register(u0);\n"
|
||||
"Texture2D<float4> src : register(t0);\n"
|
||||
"RWByteAddressBuffer 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 width, height;\n"
|
||||
" src.GetDimensions(width, height);\n"
|
||||
" uint rowBytes = width * 3;\n"
|
||||
" uint dataWidth = ((rowBytes + 255) & ~255u) / 4;\n"
|
||||
" if (dt.x >= dataWidth || dt.y >= height)\n"
|
||||
" return;\n"
|
||||
" uint rowOffset = dt.x * 4;\n"
|
||||
" if (rowOffset >= rowBytes)\n"
|
||||
" {\n"
|
||||
" dst.Store((dt.y * dataWidth + dt.x) * 4, 0);\n"
|
||||
" return;\n"
|
||||
" }\n"
|
||||
" uint firstX = (dt.x * 4) / 3;\n"
|
||||
" uint secondX = firstX + 1;\n"
|
||||
" float4 color0 = src[uint2(firstX, dt.y)];\n"
|
||||
" float4 color3 = secondX < width ?\n"
|
||||
" src[uint2(secondX, dt.y)] : 0.0f;\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"
|
||||
" float4 packed = float4(\n"
|
||||
" color0.bgr[xmod3], color1.grb[xmod3],\n"
|
||||
" color2.rbg[xmod3], color3.bgr[xmod3]);\n"
|
||||
" uint4 bytes = (uint4)(saturate(packed) * 255.0f + 0.5f);\n"
|
||||
" uint value = bytes.x | (bytes.y << 8) |\n"
|
||||
" (bytes.z << 16) | (bytes.w << 24);\n"
|
||||
" dst.Store((dt.y * dataWidth + dt.x) * 4, value);\n"
|
||||
"}\n";
|
||||
|
||||
return InitCompute(device, ranges, ARRAYSIZE(ranges), nullptr, 0, shader);
|
||||
if (!InitCompute(device, ranges, ARRAYSIZE(ranges), nullptr, 0, shader))
|
||||
return false;
|
||||
|
||||
m_state = std::make_shared<State>();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRGB24Effect::ShareState(const CPostProcessEffect& other)
|
||||
{
|
||||
m_state = static_cast<const CRGB24Effect&>(other).m_state;
|
||||
}
|
||||
|
||||
void CRGB24Effect::Update(const D12FrameFormat& format)
|
||||
{
|
||||
m_state->Update(format);
|
||||
}
|
||||
|
||||
bool CRGB24Effect::NeedsReconfigure() const
|
||||
{
|
||||
return m_state->WantsPacked() != Enabled;
|
||||
}
|
||||
|
||||
bool CRGB24Effect::RequiresFullDamage() const
|
||||
{
|
||||
return m_state->IsBenchmarking();
|
||||
}
|
||||
|
||||
uint64_t CRGB24Effect::GetTimingToken() const
|
||||
{
|
||||
return m_state->GetTimingToken(Enabled);
|
||||
}
|
||||
|
||||
void CRGB24Effect::RecordTiming(
|
||||
uint64_t token, bool fullCopy, uint64_t totalTime)
|
||||
{
|
||||
m_state->RecordTiming(token, fullCopy, totalTime);
|
||||
}
|
||||
|
||||
bool CRGB24Effect::GetCopyLayout(
|
||||
unsigned * pitch, unsigned * dataHeight) const
|
||||
{
|
||||
*pitch = m_pitch;
|
||||
*dataHeight = m_height;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void GetCopySpan(const RECT& rect, unsigned width,
|
||||
unsigned pitch, UINT64 * left, UINT64 * right)
|
||||
{
|
||||
// Damage stays in logical pixels until the packed copy is recorded.
|
||||
*left = ((UINT64)rect.left * 3) & ~3ULL;
|
||||
if (rect.left == 0 && rect.right == (LONG)width)
|
||||
*right = pitch;
|
||||
else
|
||||
*right = ((UINT64)rect.right * 3 + 3) & ~3ULL;
|
||||
}
|
||||
|
||||
bool CRGB24Effect::ShouldCopyFully(
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects) const
|
||||
{
|
||||
static const unsigned commandLimit = 256;
|
||||
|
||||
const uint64_t frameSize = (uint64_t)m_pitch * m_height;
|
||||
uint64_t copiedBytes = 0;
|
||||
unsigned commands = 0;
|
||||
for (const RECT * rect = dirtyRects;
|
||||
rect < dirtyRects + nbDirtyRects; ++rect)
|
||||
{
|
||||
UINT64 left;
|
||||
UINT64 right;
|
||||
GetCopySpan(*rect, m_width, m_pitch, &left, &right);
|
||||
|
||||
const unsigned rows = (unsigned)(rect->bottom - rect->top);
|
||||
if (left == 0 && right == m_pitch)
|
||||
{
|
||||
++commands;
|
||||
copiedBytes += (uint64_t)rows * m_pitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
commands += rows;
|
||||
copiedBytes += (right - left) * rows;
|
||||
}
|
||||
|
||||
if (commands > commandLimit || copiedBytes >= frameSize)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CRGB24Effect::CopyFrame(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
ID3D12Resource * dst, ID3D12Resource * src,
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
|
||||
{
|
||||
if (fullCopy)
|
||||
{
|
||||
commandList->CopyBufferRegion(
|
||||
dst, 0, src, 0, (UINT64)m_pitch * m_height);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const RECT * rect = dirtyRects;
|
||||
rect < dirtyRects + nbDirtyRects; ++rect)
|
||||
{
|
||||
UINT64 left;
|
||||
UINT64 right;
|
||||
GetCopySpan(*rect, m_width, m_pitch, &left, &right);
|
||||
|
||||
if (left == 0 && right == m_pitch)
|
||||
{
|
||||
const UINT64 offset = (UINT64)rect->top * m_pitch;
|
||||
const UINT64 size =
|
||||
(UINT64)(rect->bottom - rect->top) * m_pitch;
|
||||
commandList->CopyBufferRegion(dst, offset, src, offset, size);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (LONG y = rect->top; y < rect->bottom; ++y)
|
||||
{
|
||||
const UINT64 offset = (UINT64)y * m_pitch + left;
|
||||
commandList->CopyBufferRegion(
|
||||
dst, offset, src, offset, right - left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PostProcessStatus CRGB24Effect::SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||
{
|
||||
if (src.desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM)
|
||||
if (!m_state->WantsPacked())
|
||||
{
|
||||
m_dst.Reset();
|
||||
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 (src.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||
src.desc.Format != DXGI_FORMAT_B8G8R8A8_UNORM ||
|
||||
src.hdr)
|
||||
{
|
||||
DEBUG_WARN("RGB24 packing is unavailable for the current format");
|
||||
m_state->Reject();
|
||||
m_dst.Reset();
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
}
|
||||
|
||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
||||
return PostProcessStatus::FAILED;
|
||||
if (src.desc.Width >
|
||||
(UINT64_MAX - (D3D12_TEXTURE_DATA_PITCH_ALIGNMENT - 1)) / 3)
|
||||
{
|
||||
m_state->Reject();
|
||||
m_dst.Reset();
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
}
|
||||
|
||||
m_threadsX = ((unsigned)desc.Width + (Threads - 1)) / Threads;
|
||||
m_threadsY = ((unsigned)desc.Height + (Threads - 1)) / Threads;
|
||||
const UINT64 packedPitch = AlignTo<UINT64>(
|
||||
src.desc.Width * 3, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
if (!src.desc.Height || packedPitch > LONG_MAX ||
|
||||
packedPitch > UINT64_MAX / src.desc.Height)
|
||||
{
|
||||
m_state->Reject();
|
||||
m_dst.Reset();
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
}
|
||||
|
||||
dst.desc = desc;
|
||||
const UINT64 bufferSize = packedPitch * src.desc.Height;
|
||||
const UINT64 maxUAVSize =
|
||||
(1ULL << D3D12_REQ_BUFFER_RESOURCE_TEXEL_COUNT_2_TO_EXP) *
|
||||
sizeof(uint32_t);
|
||||
if (bufferSize > UINT32_MAX || bufferSize > maxUAVSize)
|
||||
{
|
||||
m_state->Reject();
|
||||
m_dst.Reset();
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
}
|
||||
|
||||
if (!CreateDefaultBuffer(device, bufferSize, m_dst))
|
||||
{
|
||||
m_state->Reject();
|
||||
m_dst.Reset();
|
||||
return PostProcessStatus::BYPASS_EFFECT;
|
||||
}
|
||||
|
||||
const unsigned dataWidth = (unsigned)(packedPitch / 4);
|
||||
m_threadsX = (dataWidth + (Threads - 1)) / Threads;
|
||||
m_threadsY = (src.desc.Height + (Threads - 1)) / Threads;
|
||||
m_width = (unsigned)src.desc.Width;
|
||||
m_height = src.desc.Height;
|
||||
m_pitch = (unsigned)packedPitch;
|
||||
|
||||
dst.desc = m_dst->GetDesc();
|
||||
dst.dataWidth = dataWidth;
|
||||
dst.dataHeight = src.desc.Height;
|
||||
dst.pitch = m_pitch;
|
||||
dst.format = FRAME_TYPE_BGR_32;
|
||||
return PostProcessStatus::SUCCESS;
|
||||
}
|
||||
@@ -94,7 +542,7 @@ ComPtr<ID3D12Resource> CRGB24Effect::Run(const ComPtr<ID3D12Device3>& device,
|
||||
UNREFERENCED_PARAMETER(dirtyRects);
|
||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COPY_SOURCE,
|
||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle =
|
||||
@@ -111,23 +559,19 @@ ComPtr<ID3D12Resource> CRGB24Effect::Run(const ComPtr<ID3D12Device3>& device,
|
||||
handle.ptr += inc;
|
||||
|
||||
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
|
||||
uavDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2D;
|
||||
uavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
|
||||
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
|
||||
uavDesc.Buffer.NumElements = (UINT)(m_dst->GetDesc().Width / 4);
|
||||
uavDesc.Buffer.StructureByteStride = 0;
|
||||
uavDesc.Buffer.CounterOffsetInBytes = 0;
|
||||
uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
|
||||
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)
|
||||
{
|
||||
const LONG left = rect->left;
|
||||
const LONG right = rect->right;
|
||||
rect->left = (left * 3) / 4;
|
||||
rect->right = (right * 3 + 3) / 4;
|
||||
}
|
||||
D3D12_RESOURCE_STATE_COMMON);
|
||||
|
||||
return m_dst;
|
||||
}
|
||||
|
||||
@@ -24,10 +24,33 @@
|
||||
|
||||
class CRGB24Effect : public CComputeEffect
|
||||
{
|
||||
private:
|
||||
struct State;
|
||||
std::shared_ptr<State> m_state;
|
||||
unsigned m_width = 0;
|
||||
unsigned m_height = 0;
|
||||
unsigned m_pitch = 0;
|
||||
|
||||
public:
|
||||
const char * GetName() const override { return "RGB24"; }
|
||||
|
||||
bool Init(const ComPtr<ID3D12Device3>& device);
|
||||
void ShareState(const CPostProcessEffect& other) override;
|
||||
void Update(const D12FrameFormat& format) override;
|
||||
bool NeedsReconfigure() const override;
|
||||
bool RequiresFullDamage() const override;
|
||||
uint64_t GetTimingToken() const override;
|
||||
void RecordTiming(
|
||||
uint64_t token, bool fullCopy, uint64_t totalTime) override;
|
||||
bool GetCopyLayout(
|
||||
unsigned * pitch, unsigned * dataHeight) const override;
|
||||
bool ShouldCopyFully(
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects) const override;
|
||||
void CopyFrame(
|
||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||
ID3D12Resource * dst, ID3D12Resource * src,
|
||||
const RECT dirtyRects[], unsigned nbDirtyRects,
|
||||
bool fullCopy) const override;
|
||||
|
||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||
|
||||
Reference in New Issue
Block a user