mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-22 15:11:31 +00:00
[idd] capture: execute texture frame graphs
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
<ClCompile Include="display\CMonitorContext.cpp" />
|
<ClCompile Include="display\CMonitorContext.cpp" />
|
||||||
<ClCompile Include="capture\CFrameBufferPool.cpp" />
|
<ClCompile Include="capture\CFrameBufferPool.cpp" />
|
||||||
<ClCompile Include="capture\CFrameBufferResource.cpp" />
|
<ClCompile Include="capture\CFrameBufferResource.cpp" />
|
||||||
|
<ClCompile Include="capture\CFrameExec.cpp" />
|
||||||
<ClCompile Include="capture\CFrameGraph.cpp" />
|
<ClCompile Include="capture\CFrameGraph.cpp" />
|
||||||
<ClCompile Include="capture\CFrameTex.cpp" />
|
<ClCompile Include="capture\CFrameTex.cpp" />
|
||||||
<ClCompile Include="capture\CFrameProcessor.cpp" />
|
<ClCompile Include="capture\CFrameProcessor.cpp" />
|
||||||
@@ -62,6 +63,7 @@
|
|||||||
<ClCompile Include="postprocess\effect\CColorTransformEffect.cpp" />
|
<ClCompile Include="postprocess\effect\CColorTransformEffect.cpp" />
|
||||||
<ClCompile Include="postprocess\effect\CComputeEffect.cpp" />
|
<ClCompile Include="postprocess\effect\CComputeEffect.cpp" />
|
||||||
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp" />
|
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp" />
|
||||||
|
<ClCompile Include="postprocess\effect\CFormatEffect.cpp" />
|
||||||
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp" />
|
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp" />
|
||||||
<ClCompile Include="postprocess\effect\CRGB24Effect.cpp" />
|
<ClCompile Include="postprocess\effect\CRGB24Effect.cpp" />
|
||||||
<ClCompile Include="transport\CControlHub.cpp" />
|
<ClCompile Include="transport\CControlHub.cpp" />
|
||||||
@@ -99,6 +101,7 @@
|
|||||||
<ClInclude Include="display\CMonitorContext.h" />
|
<ClInclude Include="display\CMonitorContext.h" />
|
||||||
<ClInclude Include="capture\CFrameBufferPool.h" />
|
<ClInclude Include="capture\CFrameBufferPool.h" />
|
||||||
<ClInclude Include="capture\CFrameBufferResource.h" />
|
<ClInclude Include="capture\CFrameBufferResource.h" />
|
||||||
|
<ClInclude Include="capture\CFrameExec.h" />
|
||||||
<ClInclude Include="capture\CFrameGraph.h" />
|
<ClInclude Include="capture\CFrameGraph.h" />
|
||||||
<ClInclude Include="capture\CFrameTex.h" />
|
<ClInclude Include="capture\CFrameTex.h" />
|
||||||
<ClInclude Include="capture\CFrameProcessor.h" />
|
<ClInclude Include="capture\CFrameProcessor.h" />
|
||||||
@@ -119,6 +122,7 @@
|
|||||||
<ClInclude Include="postprocess\effect\CColorTransformEffect.h" />
|
<ClInclude Include="postprocess\effect\CColorTransformEffect.h" />
|
||||||
<ClInclude Include="postprocess\effect\CComputeEffect.h" />
|
<ClInclude Include="postprocess\effect\CComputeEffect.h" />
|
||||||
<ClInclude Include="postprocess\effect\CDownsampleEffect.h" />
|
<ClInclude Include="postprocess\effect\CDownsampleEffect.h" />
|
||||||
|
<ClInclude Include="postprocess\effect\CFormatEffect.h" />
|
||||||
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h" />
|
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h" />
|
||||||
<ClInclude Include="postprocess\effect\CRGB24Effect.h" />
|
<ClInclude Include="postprocess\effect\CRGB24Effect.h" />
|
||||||
<ClInclude Include="transport\CControlHub.h" />
|
<ClInclude Include="transport\CControlHub.h" />
|
||||||
|
|||||||
@@ -97,6 +97,9 @@
|
|||||||
<ClInclude Include="capture\CFrameBufferResource.h">
|
<ClInclude Include="capture\CFrameBufferResource.h">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="capture\CFrameExec.h">
|
||||||
|
<Filter>Capture</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="capture\CFrameGraph.h">
|
<ClInclude Include="capture\CFrameGraph.h">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -157,6 +160,9 @@
|
|||||||
<ClInclude Include="postprocess\effect\CDownsampleEffect.h">
|
<ClInclude Include="postprocess\effect\CDownsampleEffect.h">
|
||||||
<Filter>Post-processing\Effects</Filter>
|
<Filter>Post-processing\Effects</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="postprocess\effect\CFormatEffect.h">
|
||||||
|
<Filter>Post-processing\Effects</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h">
|
<ClInclude Include="postprocess\effect\CHDR16to10Effect.h">
|
||||||
<Filter>Post-processing\Effects</Filter>
|
<Filter>Post-processing\Effects</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -294,6 +300,9 @@
|
|||||||
<ClCompile Include="capture\CFrameBufferResource.cpp">
|
<ClCompile Include="capture\CFrameBufferResource.cpp">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="capture\CFrameExec.cpp">
|
||||||
|
<Filter>Capture</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="capture\CFrameGraph.cpp">
|
<ClCompile Include="capture\CFrameGraph.cpp">
|
||||||
<Filter>Capture</Filter>
|
<Filter>Capture</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -351,6 +360,9 @@
|
|||||||
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp">
|
<ClCompile Include="postprocess\effect\CDownsampleEffect.cpp">
|
||||||
<Filter>Post-processing\Effects</Filter>
|
<Filter>Post-processing\Effects</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="postprocess\effect\CFormatEffect.cpp">
|
||||||
|
<Filter>Post-processing\Effects</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp">
|
<ClCompile Include="postprocess\effect\CHDR16to10Effect.cpp">
|
||||||
<Filter>Post-processing\Effects</Filter>
|
<Filter>Post-processing\Effects</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
773
idd/LGIdd/capture/CFrameExec.cpp
Normal file
773
idd/LGIdd/capture/CFrameExec.cpp
Normal file
@@ -0,0 +1,773 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "capture/CFrameExec.h"
|
||||||
|
|
||||||
|
#include "d3d/CD3D11Device.h"
|
||||||
|
#include "d3d/CD3D12Device.h"
|
||||||
|
#include "d3d/CInteropPool.h"
|
||||||
|
#include "d3d/CInteropResource.h"
|
||||||
|
#include "postprocess/effect/CColorTransformEffect.h"
|
||||||
|
#include "postprocess/effect/CDownsampleEffect.h"
|
||||||
|
#include "postprocess/effect/CFormatEffect.h"
|
||||||
|
#include "postprocess/effect/CHDR16to10Effect.h"
|
||||||
|
#include "transport/CTexHub.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <new>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
static const unsigned EXEC_LANES = 2;
|
||||||
|
static const unsigned EXEC_SLOTS = 4;
|
||||||
|
|
||||||
|
enum class ExecOp : uint8_t
|
||||||
|
{
|
||||||
|
COPY,
|
||||||
|
CAL,
|
||||||
|
LUT,
|
||||||
|
SCALE,
|
||||||
|
HDR10,
|
||||||
|
FORMAT,
|
||||||
|
};
|
||||||
|
|
||||||
|
D12FrameFormat MakeFormat(const FrameProfile& profile,
|
||||||
|
unsigned width, unsigned height,
|
||||||
|
const std::shared_ptr<const D12ColorTransform>& transform,
|
||||||
|
D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE)
|
||||||
|
{
|
||||||
|
D12FrameFormat format = {};
|
||||||
|
D12::Set(format,
|
||||||
|
Frame::Store(profile, FrameStorage::D3D12_TEXTURE),
|
||||||
|
width, height, flags);
|
||||||
|
format.colorTransform = transform;
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Copy(ID3D12GraphicsCommandList * list,
|
||||||
|
ID3D12Resource * src, ID3D12Resource * dst)
|
||||||
|
{
|
||||||
|
if (!list || !src || !dst || src == dst)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const D3D12_RESOURCE_DESC in = src->GetDesc();
|
||||||
|
const D3D12_RESOURCE_DESC out = dst->GetDesc();
|
||||||
|
if (!D12::Same(in, out, D12::DescCmp::COPY))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Leave the immutable input in COMMON. COPY_SOURCE is promoted
|
||||||
|
// implicitly, allowing the legacy and texture queues to read it without
|
||||||
|
// cross-queue state ownership. Only this private destination transitions.
|
||||||
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
|
barrier.Transition.pResource = dst;
|
||||||
|
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON;
|
||||||
|
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;
|
||||||
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
list->ResourceBarrier(1, &barrier);
|
||||||
|
list->CopyResource(dst, src);
|
||||||
|
std::swap(barrier.Transition.StateBefore,
|
||||||
|
barrier.Transition.StateAfter);
|
||||||
|
list->ResourceBarrier(1, &barrier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CfgResult CfgFromTex(TexResult result)
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case TexResult::OK:
|
||||||
|
return CfgResult::ACCEPTED;
|
||||||
|
case TexResult::BUSY:
|
||||||
|
return CfgResult::RETRY;
|
||||||
|
case TexResult::REJECTED:
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
case TexResult::FAILED:
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
}
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Supports(ID3D12Device3 * device, ExecOp op,
|
||||||
|
DXGI_FORMAT src, DXGI_FORMAT dst)
|
||||||
|
{
|
||||||
|
if (op == ExecOp::COPY)
|
||||||
|
return true;
|
||||||
|
D3D12_FEATURE_DATA_FORMAT_SUPPORT input = { src };
|
||||||
|
D3D12_FEATURE_DATA_FORMAT_SUPPORT output = { dst };
|
||||||
|
if (!device || FAILED(device->CheckFeatureSupport(
|
||||||
|
D3D12_FEATURE_FORMAT_SUPPORT, &input, sizeof(input))) ||
|
||||||
|
FAILED(device->CheckFeatureSupport(
|
||||||
|
D3D12_FEATURE_FORMAT_SUPPORT, &output, sizeof(output))))
|
||||||
|
return false;
|
||||||
|
const D3D12_FORMAT_SUPPORT1 read = op == ExecOp::SCALE ?
|
||||||
|
D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE :
|
||||||
|
D3D12_FORMAT_SUPPORT1_SHADER_LOAD;
|
||||||
|
return (input.Support1 & read) == read &&
|
||||||
|
(output.Support2 & D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE) != 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CFrameExec::Core : std::enable_shared_from_this<CFrameExec::Core>
|
||||||
|
{
|
||||||
|
struct Fx
|
||||||
|
{
|
||||||
|
ExecOp op = ExecOp::COPY;
|
||||||
|
ComPtr<ID3D12Resource> scratch;
|
||||||
|
std::unique_ptr<CColorTransformEffect> color;
|
||||||
|
std::unique_ptr<CDownsampleEffect> scale;
|
||||||
|
std::unique_ptr<CHDR16to10Effect> hdr;
|
||||||
|
std::unique_ptr<CFormatEffect> convert;
|
||||||
|
|
||||||
|
bool Init(const ComPtr<ID3D12Device3>& device, ExecOp selected,
|
||||||
|
const D12FrameFormat& src, const D12FrameFormat& dst, bool exported)
|
||||||
|
{
|
||||||
|
op = selected;
|
||||||
|
|
||||||
|
PostProcessStatus status = PostProcessStatus::SUCCESS;
|
||||||
|
D12FrameFormat output = src;
|
||||||
|
output.desc.Flags = dst.desc.Flags;
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case ExecOp::COPY:
|
||||||
|
if (src.desc.Width != dst.desc.Width ||
|
||||||
|
src.desc.Height != dst.desc.Height ||
|
||||||
|
src.desc.Format != dst.desc.Format)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExecOp::CAL:
|
||||||
|
color.reset(new (std::nothrow)
|
||||||
|
CColorTransformEffect(CalPart::MATRIX, true));
|
||||||
|
if (!color || !color->Init(device))
|
||||||
|
return false;
|
||||||
|
status = color->Cfg(device, src, output);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExecOp::LUT:
|
||||||
|
color.reset(new (std::nothrow)
|
||||||
|
CColorTransformEffect(CalPart::LUT, true));
|
||||||
|
if (!color || !color->Init(device))
|
||||||
|
return false;
|
||||||
|
status = color->Cfg(device, src, output);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExecOp::SCALE:
|
||||||
|
scale.reset(new (std::nothrow)
|
||||||
|
CDownsampleEffect(dst.width, dst.height));
|
||||||
|
if (!scale || !scale->Init(device))
|
||||||
|
return false;
|
||||||
|
status = scale->Cfg(device, src, output);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExecOp::HDR10:
|
||||||
|
hdr.reset(new (std::nothrow) CHDR16to10Effect);
|
||||||
|
if (!hdr || !hdr->Init(device))
|
||||||
|
return false;
|
||||||
|
status = hdr->Cfg(device, src, output);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ExecOp::FORMAT:
|
||||||
|
convert.reset(new (std::nothrow) CFormatEffect);
|
||||||
|
if (!convert || !convert->Init(device))
|
||||||
|
return false;
|
||||||
|
status = convert->Cfg(device, src, dst);
|
||||||
|
output = dst;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != PostProcessStatus::SUCCESS ||
|
||||||
|
!D12::Same(output, dst, D12::FormatCmp::IMAGE))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!exported && !PostProcessUtil::CreateDefaultTexture(
|
||||||
|
device, dst.desc, scratch))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Run(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& list,
|
||||||
|
ID3D12Resource * src, ID3D12Resource * dst)
|
||||||
|
{
|
||||||
|
if (!src || !dst)
|
||||||
|
return false;
|
||||||
|
if (op == ExecOp::COPY)
|
||||||
|
return Copy(list.Get(), src, dst);
|
||||||
|
|
||||||
|
ComPtr<ID3D12Resource> input = src;
|
||||||
|
RECT rect = {};
|
||||||
|
unsigned count = 0;
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case ExecOp::CAL:
|
||||||
|
case ExecOp::LUT:
|
||||||
|
return color && color->Run(
|
||||||
|
device, list, input, dst, &rect, &count);
|
||||||
|
case ExecOp::SCALE:
|
||||||
|
return scale && scale->Run(
|
||||||
|
device, list, input, dst, &rect, &count);
|
||||||
|
case ExecOp::HDR10:
|
||||||
|
return hdr && hdr->Run(
|
||||||
|
device, list, input, dst, &rect, &count);
|
||||||
|
case ExecOp::FORMAT:
|
||||||
|
return convert && convert->Run(
|
||||||
|
device, list, input, dst, &rect, &count);
|
||||||
|
case ExecOp::COPY:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Lane
|
||||||
|
{
|
||||||
|
Fx nodes[FRAME_GRAPH_MAX_NODES];
|
||||||
|
};
|
||||||
|
|
||||||
|
CSRWLock runLock;
|
||||||
|
std::shared_ptr<CD3D11Device> d11;
|
||||||
|
std::shared_ptr<CD3D12Device> d12;
|
||||||
|
ComPtr<ID3D12Device3> device;
|
||||||
|
CTexHub * hub = nullptr;
|
||||||
|
CFrameGraph graph;
|
||||||
|
CD3D12CommandQueue queue;
|
||||||
|
CTexPool pools[FRAME_GRAPH_MAX_NODES];
|
||||||
|
CInteropPool interop[FRAME_GRAPH_MAX_NODES];
|
||||||
|
Lane lanes[EXEC_LANES];
|
||||||
|
D12FrameFormat formats[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
ExecOp ops[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
bool exported[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
bool d11Node[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
unsigned readers[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
unsigned nodeCount = 0;
|
||||||
|
unsigned leafCount = 0;
|
||||||
|
unsigned nextLane = 0;
|
||||||
|
bool live = false;
|
||||||
|
std::atomic<bool> forceFull { true };
|
||||||
|
|
||||||
|
~Core()
|
||||||
|
{
|
||||||
|
// Effect descriptor heaps, scratch textures, and pool destinations are
|
||||||
|
// referenced by submitted lists. Drain before member destruction.
|
||||||
|
queue.WaitForIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Select(const GraphNode& parent,
|
||||||
|
const GraphNode& node, ExecOp& op)
|
||||||
|
{
|
||||||
|
switch (node.op)
|
||||||
|
{
|
||||||
|
case FrameOp::CAL:
|
||||||
|
op = ExecOp::CAL;
|
||||||
|
return true;
|
||||||
|
case FrameOp::LUT:
|
||||||
|
op = ExecOp::LUT;
|
||||||
|
return true;
|
||||||
|
case FrameOp::SCALE:
|
||||||
|
op = ExecOp::SCALE;
|
||||||
|
return true;
|
||||||
|
case FrameOp::HDR10:
|
||||||
|
if (parent.profile.signal == FrameSignal::SCRGB_LINEAR &&
|
||||||
|
node.profile.signal == FrameSignal::PQ_BT2020)
|
||||||
|
{
|
||||||
|
op = ExecOp::HDR10;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FrameOp::SDR:
|
||||||
|
case FrameOp::SCRGB:
|
||||||
|
break;
|
||||||
|
case FrameOp::SRC:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent.width == node.width && parent.height == node.height &&
|
||||||
|
Frame::Same(parent.profile, node.profile))
|
||||||
|
{
|
||||||
|
op = ExecOp::COPY;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (parent.width == node.width && parent.height == node.height &&
|
||||||
|
parent.profile.signal == FrameSignal::SRGB &&
|
||||||
|
node.profile.signal == FrameSignal::SRGB &&
|
||||||
|
parent.profile.pixel != node.profile.pixel)
|
||||||
|
{
|
||||||
|
op = ExecOp::FORMAT;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CfgResult Init(const CFrameGraph& source,
|
||||||
|
const std::shared_ptr<CD3D11Device>& d11Device,
|
||||||
|
const std::shared_ptr<CD3D12Device>& d12Device, CTexHub& texHub)
|
||||||
|
{
|
||||||
|
d11 = d11Device;
|
||||||
|
d12 = d12Device;
|
||||||
|
hub = &texHub;
|
||||||
|
graph = source;
|
||||||
|
device = d12 ? d12->GetDevice() : nullptr;
|
||||||
|
if (!d11 || !d12 || !device || !graph.Generation())
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
|
||||||
|
const GraphNode * nodes = graph.Nodes(nodeCount);
|
||||||
|
const GraphLeaf * leaves = graph.Leaves(leafCount);
|
||||||
|
if (!nodes || !leaves || !nodeCount ||
|
||||||
|
nodeCount > FRAME_GRAPH_MAX_NODES ||
|
||||||
|
leafCount > TRANSPORT_MAX_INSTANCES)
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
|
||||||
|
unsigned texLeaves = 0;
|
||||||
|
for (unsigned leaf = 0; leaf < leafCount; ++leaf)
|
||||||
|
if (leaves[leaf].tex)
|
||||||
|
{
|
||||||
|
if (!leaves[leaf].node || leaves[leaf].node >= nodeCount)
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
exported[leaves[leaf].node] = true;
|
||||||
|
++readers[leaves[leaf].node];
|
||||||
|
d11Node[leaves[leaf].node] |=
|
||||||
|
leaves[leaf].cfg.profile.storage ==
|
||||||
|
FrameStorage::D3D11_TEXTURE;
|
||||||
|
++texLeaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!texLeaves)
|
||||||
|
return CfgResult::ACCEPTED;
|
||||||
|
if (!nodes[0].texRefs || !queue.Init(device.Get(),
|
||||||
|
D3D12_COMMAND_LIST_TYPE_DIRECT, L"Frame Graph",
|
||||||
|
CD3D12CommandSlot::FAST, EXEC_LANES, false, true))
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
|
||||||
|
const GraphCfg& cfg = graph.Cfg();
|
||||||
|
formats[0] = MakeFormat(cfg.src, cfg.srcWidth, cfg.srcHeight,
|
||||||
|
cfg.transform);
|
||||||
|
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
{
|
||||||
|
if (!nodes[node].texRefs)
|
||||||
|
continue;
|
||||||
|
if (nodes[node].texRefs > nodes[node].refs ||
|
||||||
|
nodes[node].parent >= node ||
|
||||||
|
!nodes[nodes[node].parent].texRefs ||
|
||||||
|
!Select(nodes[nodes[node].parent], nodes[node], ops[node]))
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
|
||||||
|
D3D12_RESOURCE_FLAGS flags = ops[node] == ExecOp::COPY &&
|
||||||
|
exported[node] ?
|
||||||
|
D3D12_RESOURCE_FLAG_NONE :
|
||||||
|
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
||||||
|
if (exported[node] && readers[node] > 1)
|
||||||
|
flags |= D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS;
|
||||||
|
formats[node] = MakeFormat(nodes[node].profile,
|
||||||
|
nodes[node].width, nodes[node].height, cfg.transform, flags);
|
||||||
|
if (!Supports(device.Get(), ops[node],
|
||||||
|
formats[nodes[node].parent].desc.Format,
|
||||||
|
formats[node].desc.Format))
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
|
||||||
|
if (exported[node])
|
||||||
|
{
|
||||||
|
const FrameProfile profile = Frame::Store(
|
||||||
|
nodes[node].profile, FrameStorage::D3D12_TEXTURE);
|
||||||
|
const TexResult result = pools[node].Init(device.Get(),
|
||||||
|
graph.Generation(), node, profile, formats[node].desc,
|
||||||
|
D3D12_RESOURCE_STATE_COMMON, EXEC_SLOTS, graph.Shared(node));
|
||||||
|
if (result != TexResult::OK)
|
||||||
|
return CfgFromTex(result);
|
||||||
|
if (d11Node[node])
|
||||||
|
{
|
||||||
|
const TexResult interopResult = interop[node].Init(d11, d12);
|
||||||
|
if (interopResult != TexResult::OK)
|
||||||
|
return CfgFromTex(interopResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned lane = 0; lane < EXEC_LANES; ++lane)
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
if (nodes[node].texRefs && !lanes[lane].nodes[node].Init(
|
||||||
|
device, ops[node], formats[nodes[node].parent], formats[node],
|
||||||
|
exported[node]))
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
|
||||||
|
live = true;
|
||||||
|
return CfgResult::ACCEPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
FrameContentRef Content(uint64_t serial, const D12FrameFormat& format,
|
||||||
|
uint64_t captureTime, bool full, FrameDamage damage,
|
||||||
|
const RECT * rects, unsigned count)
|
||||||
|
{
|
||||||
|
if (!serial || count > FRAME_DAMAGE_MAX ||
|
||||||
|
(count && !rects) ||
|
||||||
|
(damage == FrameDamage::RECTS) != (count != 0))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
FrameContent * raw = new (std::nothrow) FrameContent;
|
||||||
|
if (!raw)
|
||||||
|
return {};
|
||||||
|
raw->serial = serial;
|
||||||
|
raw->captureTime = captureTime;
|
||||||
|
raw->damage = full ? FrameDamage::FULL : damage;
|
||||||
|
raw->count = raw->damage == FrameDamage::RECTS ? count : 0;
|
||||||
|
if (raw->count)
|
||||||
|
memcpy(raw->rects, rects, raw->count * sizeof(*rects));
|
||||||
|
raw->format = format;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return FrameContentRef(raw);
|
||||||
|
}
|
||||||
|
catch (const std::bad_alloc&)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult Run(CInteropResource& src, const D12FrameFormat& sourceFormat,
|
||||||
|
uint64_t serial, uint64_t captureTime, uint64_t postStart,
|
||||||
|
FrameDamage damage, const RECT * rects, unsigned count) noexcept
|
||||||
|
{
|
||||||
|
if (!live)
|
||||||
|
return TexResult::OK;
|
||||||
|
|
||||||
|
CSRWExclusiveLock run = CSRWExclusiveLock::Try(runLock);
|
||||||
|
if (!run)
|
||||||
|
{
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::BUSY;
|
||||||
|
}
|
||||||
|
const bool full = Atomic::Swap(forceFull, false, std::memory_order_acq_rel);
|
||||||
|
|
||||||
|
ID3D12Resource * source = src.GetRes().Get();
|
||||||
|
if (!source)
|
||||||
|
{
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
}
|
||||||
|
const D3D12_RESOURCE_DESC actual = source->GetDesc();
|
||||||
|
if (!D12::Same(actual, sourceFormat.desc, D12::DescCmp::COPY))
|
||||||
|
{
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameContentRef content = Content(
|
||||||
|
serial, sourceFormat, captureTime, full, damage, rects, count);
|
||||||
|
FrameDesc check;
|
||||||
|
unsigned first = 0;
|
||||||
|
while (++first < nodeCount && !exported[first]) {}
|
||||||
|
if (!content || first == nodeCount ||
|
||||||
|
!graph.Desc(first, content, check))
|
||||||
|
{
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::REJECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
CD3D12CommandSlot * slot = nullptr;
|
||||||
|
unsigned lane = 0;
|
||||||
|
for (unsigned attempt = 0; attempt < EXEC_LANES; ++attempt)
|
||||||
|
{
|
||||||
|
lane = (nextLane + attempt) % EXEC_LANES;
|
||||||
|
slot = queue.Try(lane);
|
||||||
|
if (slot)
|
||||||
|
{
|
||||||
|
nextLane = (lane + 1) % EXEC_LANES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!slot)
|
||||||
|
{
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return queue.Failed() ? TexResult::FAILED : TexResult::BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
TexWrite writes[FRAME_GRAPH_MAX_NODES];
|
||||||
|
const GraphNode * nodes = graph.Nodes(nodeCount);
|
||||||
|
TexResult result = TexResult::OK;
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
if (exported[node])
|
||||||
|
{
|
||||||
|
result = pools[node].Try(writes[node]);
|
||||||
|
if (result != TexResult::OK)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (result != TexResult::OK)
|
||||||
|
{
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
writes[node].Cancel();
|
||||||
|
slot->Cancel();
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!src.Signal() || !src.Sync(*slot))
|
||||||
|
{
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
writes[node].Cancel();
|
||||||
|
slot->Cancel();
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<ID3D12GraphicsCommandList> list = slot->GetGfxList();
|
||||||
|
ID3D12Resource * outputs[FRAME_GRAPH_MAX_NODES] = {};
|
||||||
|
outputs[0] = source;
|
||||||
|
bool recorded = !!list && !!outputs[0];
|
||||||
|
for (unsigned node = 1; recorded && node < nodeCount; ++node)
|
||||||
|
if (nodes[node].texRefs)
|
||||||
|
{
|
||||||
|
ID3D12Resource * output = exported[node] ?
|
||||||
|
writes[node].Get() : lanes[lane].nodes[node].scratch.Get();
|
||||||
|
recorded = output && lanes[lane].nodes[node].Run(
|
||||||
|
device, list, outputs[nodes[node].parent], output);
|
||||||
|
outputs[node] = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!recorded)
|
||||||
|
{
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
writes[node].Cancel();
|
||||||
|
slot->Cancel();
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
D12Sync sync;
|
||||||
|
if (!slot->Execute(&sync))
|
||||||
|
{
|
||||||
|
const bool submitted = slot->HasSubmittedWork();
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
if (submitted)
|
||||||
|
writes[node].Fail(sync);
|
||||||
|
else
|
||||||
|
writes[node].Cancel();
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FrameTime time = { postStart, 0, 0, 0, false, false };
|
||||||
|
TexLease leases[FRAME_GRAPH_MAX_NODES];
|
||||||
|
const std::shared_ptr<void> hold = shared_from_this();
|
||||||
|
bool sealed = true;
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
if (exported[node])
|
||||||
|
{
|
||||||
|
FrameDesc desc;
|
||||||
|
if (!graph.Desc(node, content, desc) ||
|
||||||
|
!writes[node].Seal(desc, time, sync, leases[node], hold))
|
||||||
|
{
|
||||||
|
sealed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sealed)
|
||||||
|
{
|
||||||
|
for (unsigned node = 1; node < nodeCount; ++node)
|
||||||
|
{
|
||||||
|
if (writes[node])
|
||||||
|
writes[node].Fail(sync);
|
||||||
|
leases[node].Reset();
|
||||||
|
}
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
return TexResult::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dropped = false;
|
||||||
|
bool failed = false;
|
||||||
|
const GraphLeaf * leaves = graph.Leaves(leafCount);
|
||||||
|
for (unsigned leaf = 0; leaf < leafCount; ++leaf)
|
||||||
|
{
|
||||||
|
if (!leaves[leaf].tex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
FrameIn frame;
|
||||||
|
frame.graph = graph.Generation();
|
||||||
|
if (!graph.Desc(leaf, content, frame.desc))
|
||||||
|
{
|
||||||
|
dropped = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PushResult pushed = PushResult::STALE;
|
||||||
|
const unsigned node = leaves[leaf].node;
|
||||||
|
if (leaves[leaf].cfg.profile.storage ==
|
||||||
|
FrameStorage::D3D12_TEXTURE)
|
||||||
|
{
|
||||||
|
pushed = hub->Push(frame, leases[node]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
D11Lease lease;
|
||||||
|
const TexResult opened = interop[node].Get(leases[node], lease);
|
||||||
|
if (opened == TexResult::OK)
|
||||||
|
pushed = hub->Push(frame, std::move(lease));
|
||||||
|
else if (opened == TexResult::BUSY)
|
||||||
|
pushed = PushResult::BUSY;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pushed = opened == TexResult::REJECTED ?
|
||||||
|
PushResult::REJECTED : PushResult::FAILED;
|
||||||
|
hub->Fault(frame, pushed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pushed == PushResult::BUSY || pushed == PushResult::STALE)
|
||||||
|
dropped = true;
|
||||||
|
else if (pushed == PushResult::FAILED)
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dropped)
|
||||||
|
Atomic::Store(forceFull, true, std::memory_order_release);
|
||||||
|
if (failed)
|
||||||
|
return TexResult::FAILED;
|
||||||
|
return dropped ? TexResult::BUSY : TexResult::OK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CFrameExec::~CFrameExec()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameExec::Init(const std::shared_ptr<CD3D11Device>& d11,
|
||||||
|
const std::shared_ptr<CD3D12Device>& d12, CTexHub& hub)
|
||||||
|
{
|
||||||
|
if (!d11 || !d12 || !d11->GetDevice() || !d12->GetDevice())
|
||||||
|
return false;
|
||||||
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
if (m_d11 || m_d12 || m_hub)
|
||||||
|
return false;
|
||||||
|
m_d11 = d11;
|
||||||
|
m_d12 = d12;
|
||||||
|
m_hub = &hub;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameExec::Reset()
|
||||||
|
{
|
||||||
|
std::shared_ptr<Core> active;
|
||||||
|
std::shared_ptr<Core> pending;
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
active = std::move(m_active);
|
||||||
|
pending = std::move(m_pending);
|
||||||
|
m_hub = nullptr;
|
||||||
|
m_d12.reset();
|
||||||
|
m_d11.reset();
|
||||||
|
}
|
||||||
|
pending.reset();
|
||||||
|
active.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t CFrameExec::NextSerial()
|
||||||
|
{
|
||||||
|
return Atomic::Next(m_serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
CfgResult CFrameExec::Prep(const CFrameGraph& graph) noexcept
|
||||||
|
{
|
||||||
|
std::shared_ptr<CD3D11Device> d11;
|
||||||
|
std::shared_ptr<CD3D12Device> d12;
|
||||||
|
CTexHub * hub = nullptr;
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_lock);
|
||||||
|
if (m_pending)
|
||||||
|
return CfgResult::REJECTED;
|
||||||
|
d11 = m_d11;
|
||||||
|
d12 = m_d12;
|
||||||
|
hub = m_hub;
|
||||||
|
}
|
||||||
|
if (!d11 || !d12 || !hub)
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
|
||||||
|
std::shared_ptr<Core> next;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
next.reset(new (std::nothrow) Core);
|
||||||
|
}
|
||||||
|
catch (const std::bad_alloc&)
|
||||||
|
{
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
}
|
||||||
|
if (!next)
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
|
||||||
|
CfgResult result = CfgResult::FAILED;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = next->Init(graph, d11, d12, *hub);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return CfgResult::FAILED;
|
||||||
|
}
|
||||||
|
if (result != CfgResult::ACCEPTED)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
if (m_pending || m_d11 != d11 || m_d12 != d12 || m_hub != hub)
|
||||||
|
return CfgResult::RETRY;
|
||||||
|
m_pending = next;
|
||||||
|
}
|
||||||
|
return CfgResult::ACCEPTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameExec::Commit() noexcept
|
||||||
|
{
|
||||||
|
std::shared_ptr<Core> old;
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
if (!m_pending)
|
||||||
|
return;
|
||||||
|
old = std::move(m_active);
|
||||||
|
m_active = std::move(m_pending);
|
||||||
|
}
|
||||||
|
old.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFrameExec::Abort() noexcept
|
||||||
|
{
|
||||||
|
std::shared_ptr<Core> drop;
|
||||||
|
{
|
||||||
|
CSRWExclusiveLock lock(m_lock);
|
||||||
|
drop = std::move(m_pending);
|
||||||
|
}
|
||||||
|
drop.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
TexResult CFrameExec::Run(CInteropResource& src,
|
||||||
|
const D12FrameFormat& format, uint64_t captureTime, uint64_t postStart,
|
||||||
|
FrameDamage damage, const RECT * rects, unsigned count) noexcept
|
||||||
|
{
|
||||||
|
std::shared_ptr<Core> core;
|
||||||
|
{
|
||||||
|
CSRWSharedLock lock(m_lock);
|
||||||
|
core = m_active;
|
||||||
|
}
|
||||||
|
if (!core || !core->live)
|
||||||
|
return TexResult::OK;
|
||||||
|
return core->Run(src, format, NextSerial(), captureTime, postStart,
|
||||||
|
damage, rects, count);
|
||||||
|
}
|
||||||
71
idd/LGIdd/capture/CFrameExec.h
Normal file
71
idd/LGIdd/capture/CFrameExec.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Atomic.h"
|
||||||
|
#include "CSRWLock.h"
|
||||||
|
#include "capture/CFrameGraph.h"
|
||||||
|
#include "capture/CFrameTex.h"
|
||||||
|
#include "transport/ITexStage.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
class CInteropResource;
|
||||||
|
class CTexHub;
|
||||||
|
struct CD3D11Device;
|
||||||
|
struct CD3D12Device;
|
||||||
|
|
||||||
|
// Transactional executor for texture-backed transport routes. Every product
|
||||||
|
// is materialized in executor-owned storage before the acquired IddCx surface
|
||||||
|
// is released. A graph containing only legacy routes remains fully dormant.
|
||||||
|
class CFrameExec final : public ITexStage
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
struct Core;
|
||||||
|
|
||||||
|
mutable CSRWLock m_lock;
|
||||||
|
std::shared_ptr<CD3D11Device> m_d11;
|
||||||
|
std::shared_ptr<CD3D12Device> m_d12;
|
||||||
|
CTexHub * m_hub = nullptr;
|
||||||
|
std::shared_ptr<Core> m_active;
|
||||||
|
std::shared_ptr<Core> m_pending;
|
||||||
|
std::atomic<uint64_t> m_serial { 0 };
|
||||||
|
|
||||||
|
uint64_t NextSerial();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CFrameExec() = default;
|
||||||
|
~CFrameExec();
|
||||||
|
CFrameExec(const CFrameExec&) = delete;
|
||||||
|
CFrameExec& operator=(const CFrameExec&) = delete;
|
||||||
|
|
||||||
|
bool Init(const std::shared_ptr<CD3D11Device>& d11,
|
||||||
|
const std::shared_ptr<CD3D12Device>& d12, CTexHub& hub);
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
CfgResult Prep(const CFrameGraph& graph) noexcept override;
|
||||||
|
void Commit() noexcept override;
|
||||||
|
void Abort() noexcept override;
|
||||||
|
|
||||||
|
TexResult Run(CInteropResource& src, const D12FrameFormat& format,
|
||||||
|
uint64_t captureTime, uint64_t postStart, FrameDamage damage,
|
||||||
|
const RECT * rects, unsigned count) noexcept;
|
||||||
|
};
|
||||||
@@ -241,7 +241,7 @@ unsigned CFrameGraph::Checkpoint(const FrameProfile& requested)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CFrameGraph::Add(BackendId id, uint32_t epoch, bool required,
|
bool CFrameGraph::Add(BackendId id, uint32_t epoch, bool required,
|
||||||
bool primary, const FrameCfg& cfg)
|
bool primary, bool tex, const FrameCfg& cfg)
|
||||||
{
|
{
|
||||||
if (!id || !epoch || !Can(cfg) ||
|
if (!id || !epoch || !Can(cfg) ||
|
||||||
m_leafCount == TRANSPORT_MAX_INSTANCES)
|
m_leafCount == TRANSPORT_MAX_INSTANCES)
|
||||||
@@ -266,11 +266,16 @@ bool CFrameGraph::Add(BackendId id, uint32_t epoch, bool required,
|
|||||||
leaf.node = node;
|
leaf.node = node;
|
||||||
leaf.required = required;
|
leaf.required = required;
|
||||||
leaf.primary = primary;
|
leaf.primary = primary;
|
||||||
|
leaf.tex = tex;
|
||||||
leaf.cfg = cfg;
|
leaf.cfg = cfg;
|
||||||
|
|
||||||
for (unsigned current = node;
|
for (unsigned current = node;
|
||||||
current != FRAME_GRAPH_ROOT; current = m_nodes[current].parent)
|
current != FRAME_GRAPH_ROOT; current = m_nodes[current].parent)
|
||||||
|
{
|
||||||
++m_nodes[current].refs;
|
++m_nodes[current].refs;
|
||||||
|
if (tex)
|
||||||
|
++m_nodes[current].texRefs;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,6 +289,9 @@ bool CFrameGraph::Seal()
|
|||||||
if (!m_leaves[i].id || !m_leaves[i].epoch ||
|
if (!m_leaves[i].id || !m_leaves[i].epoch ||
|
||||||
!m_leaves[i].node || m_leaves[i].node >= m_nodeCount)
|
!m_leaves[i].node || m_leaves[i].node >= m_nodeCount)
|
||||||
return false;
|
return false;
|
||||||
|
for (unsigned i = 0; i < m_nodeCount; ++i)
|
||||||
|
if (!m_nodes[i].refs || m_nodes[i].texRefs > m_nodes[i].refs)
|
||||||
|
return false;
|
||||||
|
|
||||||
m_sealed = true;
|
m_sealed = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -324,17 +332,19 @@ bool CFrameGraph::Want(FrameSignal signal) const
|
|||||||
|
|
||||||
bool CFrameGraph::Shared(unsigned node) const
|
bool CFrameGraph::Shared(unsigned node) const
|
||||||
{
|
{
|
||||||
if (!m_sealed || !node || node >= m_nodeCount)
|
if (!m_sealed || !node || node >= m_nodeCount ||
|
||||||
|
!m_nodes[node].texRefs)
|
||||||
return false;
|
return false;
|
||||||
for (unsigned i = 0; i < m_leafCount; ++i)
|
for (unsigned i = 0; i < m_leafCount; ++i)
|
||||||
if (m_leaves[i].node == node &&
|
if (m_leaves[i].tex &&
|
||||||
|
m_leaves[i].node == node &&
|
||||||
m_leaves[i].cfg.profile.storage == FrameStorage::D3D11_TEXTURE)
|
m_leaves[i].cfg.profile.storage == FrameStorage::D3D11_TEXTURE)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFrameGraph::Desc(unsigned leaf, const FrameContentRef& content,
|
bool CFrameGraph::Desc(unsigned nodeIndex,
|
||||||
LeafDesc& desc) const
|
const FrameContentRef& content, FrameDesc& desc) const
|
||||||
{
|
{
|
||||||
if (!content)
|
if (!content)
|
||||||
return false;
|
return false;
|
||||||
@@ -343,59 +353,78 @@ bool CFrameGraph::Desc(unsigned leaf, const FrameContentRef& content,
|
|||||||
FrameProfile sourceProfile;
|
FrameProfile sourceProfile;
|
||||||
const bool validProfile = D12::Profile(source,
|
const bool validProfile = D12::Profile(source,
|
||||||
FrameStorage::D3D12_TEXTURE, sourceProfile);
|
FrameStorage::D3D12_TEXTURE, sourceProfile);
|
||||||
|
const auto effectiveTransform =
|
||||||
|
D12::Transform(source.colorTransform);
|
||||||
if (!validProfile || !Frame::Same(sourceProfile, m_cfg.src))
|
if (!validProfile || !Frame::Same(sourceProfile, m_cfg.src))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!m_sealed ||
|
if (!m_sealed ||
|
||||||
leaf >= m_leafCount ||
|
!nodeIndex ||
|
||||||
!content->serial ||
|
nodeIndex >= m_nodeCount ||
|
||||||
source.width != m_cfg.srcWidth ||
|
!content->serial ||
|
||||||
source.height != m_cfg.srcHeight ||
|
source.width != m_cfg.srcWidth ||
|
||||||
source.dataWidth != m_cfg.srcWidth ||
|
source.height != m_cfg.srcHeight ||
|
||||||
source.dataHeight != m_cfg.srcHeight ||
|
source.dataWidth != m_cfg.srcWidth ||
|
||||||
source.pitch != 0 ||
|
source.dataHeight != m_cfg.srcHeight ||
|
||||||
|
source.pitch != 0 ||
|
||||||
source.desc.Dimension !=
|
source.desc.Dimension !=
|
||||||
D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||||
source.desc.Width != m_cfg.srcWidth ||
|
source.desc.Width != m_cfg.srcWidth ||
|
||||||
source.desc.Height != m_cfg.srcHeight ||
|
source.desc.Height != m_cfg.srcHeight ||
|
||||||
source.desc.DepthOrArraySize != 1 ||
|
source.desc.DepthOrArraySize != 1 ||
|
||||||
source.desc.MipLevels != 1 ||
|
source.desc.MipLevels != 1 ||
|
||||||
source.desc.SampleDesc.Count != 1 ||
|
source.desc.SampleDesc.Count != 1 ||
|
||||||
|
effectiveTransform != m_cfg.transform ||
|
||||||
!Frame::Valid(content->damage, content->rects, content->count,
|
!Frame::Valid(content->damage, content->rects, content->count,
|
||||||
m_cfg.srcWidth, m_cfg.srcHeight))
|
m_cfg.srcWidth, m_cfg.srcHeight))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const GraphLeaf& route = m_leaves[leaf];
|
const GraphNode& node = m_nodes[nodeIndex];
|
||||||
const GraphNode& node = m_nodes[route.node];
|
FrameDesc result;
|
||||||
desc.id = route.id;
|
result.content = content;
|
||||||
desc.epoch = route.epoch;
|
result.damage = content->damage;
|
||||||
desc.node = route.node;
|
result.count = content->count;
|
||||||
desc.profile = route.cfg.profile;
|
|
||||||
|
|
||||||
desc.frame = FrameDesc {};
|
|
||||||
desc.frame.content = content;
|
|
||||||
desc.frame.damage = content->damage;
|
|
||||||
desc.frame.count = content->count;
|
|
||||||
if (content->count)
|
if (content->count)
|
||||||
memcpy(desc.frame.rects, content->rects,
|
memcpy(result.rects, content->rects,
|
||||||
content->count * sizeof(*content->rects));
|
content->count * sizeof(*content->rects));
|
||||||
desc.frame.format = content->format;
|
result.format = content->format;
|
||||||
|
|
||||||
// A scaled checkpoint has a different damage coordinate space. Until the
|
// A scaled checkpoint has a different damage coordinate space. Until the
|
||||||
// executor owns exact edge transforms, preserve correctness by making any
|
// executor owns exact edge transforms, preserve correctness by making any
|
||||||
// partial source damage a full node update.
|
// partial source damage a full node update.
|
||||||
if (desc.frame.damage == FrameDamage::RECTS &&
|
if (result.damage == FrameDamage::RECTS &&
|
||||||
(node.width != m_cfg.srcWidth || node.height != m_cfg.srcHeight))
|
(node.width != m_cfg.srcWidth || node.height != m_cfg.srcHeight))
|
||||||
{
|
{
|
||||||
desc.frame.damage = FrameDamage::FULL;
|
result.damage = FrameDamage::FULL;
|
||||||
desc.frame.count = 0;
|
result.count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
D12FrameFormat& format = desc.frame.format;
|
D12FrameFormat& output = result.format;
|
||||||
if (!D12::Set(format, node.profile, node.width, node.height))
|
if (!D12::Set(output, node.profile, node.width, node.height))
|
||||||
return false;
|
return false;
|
||||||
// Calibration/LUT nodes have already consumed this transform.
|
// Calibration/LUT nodes have already consumed this transform.
|
||||||
format.colorTransform.reset();
|
output.colorTransform.reset();
|
||||||
|
|
||||||
|
desc = result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFrameGraph::Desc(unsigned leaf, const FrameContentRef& content,
|
||||||
|
LeafDesc& desc) const
|
||||||
|
{
|
||||||
|
if (!m_sealed || leaf >= m_leafCount)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const GraphLeaf& route = m_leaves[leaf];
|
||||||
|
LeafDesc result;
|
||||||
|
if (!Desc(route.node, content, result.frame))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
result.id = route.id;
|
||||||
|
result.epoch = route.epoch;
|
||||||
|
result.node = route.node;
|
||||||
|
result.profile = route.cfg.profile;
|
||||||
|
desc = result;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,9 @@ struct GraphNode
|
|||||||
{
|
{
|
||||||
FrameOp op = FrameOp::SRC;
|
FrameOp op = FrameOp::SRC;
|
||||||
unsigned parent = FRAME_GRAPH_ROOT;
|
unsigned parent = FRAME_GRAPH_ROOT;
|
||||||
|
// refs covers every route; texRefs is the direct texture-route closure.
|
||||||
unsigned refs = 0;
|
unsigned refs = 0;
|
||||||
|
unsigned texRefs = 0;
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
unsigned height = 0;
|
unsigned height = 0;
|
||||||
FrameProfile profile;
|
FrameProfile profile;
|
||||||
@@ -88,6 +90,7 @@ struct GraphLeaf
|
|||||||
unsigned node = 0;
|
unsigned node = 0;
|
||||||
bool required = false;
|
bool required = false;
|
||||||
bool primary = false;
|
bool primary = false;
|
||||||
|
bool tex = false;
|
||||||
FrameCfg cfg;
|
FrameCfg cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -149,13 +152,15 @@ public:
|
|||||||
bool Begin(const GraphCfg& cfg);
|
bool Begin(const GraphCfg& cfg);
|
||||||
bool Can(const FrameCfg& cfg) const;
|
bool Can(const FrameCfg& cfg) const;
|
||||||
bool Add(BackendId id, uint32_t epoch, bool required, bool primary,
|
bool Add(BackendId id, uint32_t epoch, bool required, bool primary,
|
||||||
const FrameCfg& cfg);
|
bool tex, const FrameCfg& cfg);
|
||||||
bool Seal();
|
bool Seal();
|
||||||
bool Stamp(uint64_t generation);
|
bool Stamp(uint64_t generation);
|
||||||
bool Same(const GraphCfg& cfg) const;
|
bool Same(const GraphCfg& cfg) const;
|
||||||
bool Want(FrameSignal signal) const;
|
bool Want(FrameSignal signal) const;
|
||||||
bool Need(FrameOp op) const;
|
bool Need(FrameOp op) const;
|
||||||
bool Shared(unsigned node) const;
|
bool Shared(unsigned node) const;
|
||||||
|
bool Desc(unsigned node, const FrameContentRef& content,
|
||||||
|
FrameDesc& desc) const;
|
||||||
bool Desc(unsigned leaf, const FrameContentRef& content,
|
bool Desc(unsigned leaf, const FrameContentRef& content,
|
||||||
LeafDesc& desc) const;
|
LeafDesc& desc) const;
|
||||||
|
|
||||||
|
|||||||
@@ -297,11 +297,13 @@ CFrameTex::CFrameTex(uint64_t graphValue, uint64_t poolValue,
|
|||||||
const FrameProfile& profileValue,
|
const FrameProfile& profileValue,
|
||||||
const FrameDesc& frameValue, const FrameTime& timeValue,
|
const FrameDesc& frameValue, const FrameTime& timeValue,
|
||||||
const ComPtr<ID3D12Resource>& res,
|
const ComPtr<ID3D12Resource>& res,
|
||||||
const D12Sync& sync, D3D12_RESOURCE_STATES state, bool sharedValue) :
|
const D12Sync& sync, D3D12_RESOURCE_STATES state, bool sharedValue,
|
||||||
|
const std::shared_ptr<void>& hold) :
|
||||||
m_res(res),
|
m_res(res),
|
||||||
m_sync(sync),
|
m_sync(sync),
|
||||||
m_state(state),
|
m_state(state),
|
||||||
m_shared(sharedValue),
|
m_shared(sharedValue),
|
||||||
|
m_hold(hold),
|
||||||
graph(graphValue),
|
graph(graphValue),
|
||||||
pool(poolValue),
|
pool(poolValue),
|
||||||
node(nodeValue),
|
node(nodeValue),
|
||||||
@@ -378,7 +380,8 @@ ID3D12Resource * TexWrite::Get() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool TexWrite::Seal(const FrameDesc& frame, const FrameTime& time,
|
bool TexWrite::Seal(const FrameDesc& frame, const FrameTime& time,
|
||||||
const D12Sync& sync, TexLease& lease)
|
const D12Sync& sync, TexLease& lease,
|
||||||
|
const std::shared_ptr<void>& hold)
|
||||||
{
|
{
|
||||||
if (!m_core || !sync.Valid())
|
if (!m_core || !sync.Valid())
|
||||||
return false;
|
return false;
|
||||||
@@ -404,7 +407,7 @@ bool TexWrite::Seal(const FrameDesc& frame, const FrameTime& time,
|
|||||||
// pool descriptor, including producer-only UAV creation capability.
|
// pool descriptor, including producer-only UAV creation capability.
|
||||||
desc.format.desc = resource->GetDesc();
|
desc.format.desc = resource->GetDesc();
|
||||||
|
|
||||||
const unsigned index = m_index;
|
const unsigned index = m_index;
|
||||||
const uint64_t generation = m_version;
|
const uint64_t generation = m_version;
|
||||||
if (!core->Seal(index, generation, sync))
|
if (!core->Seal(index, generation, sync))
|
||||||
{
|
{
|
||||||
@@ -415,7 +418,7 @@ bool TexWrite::Seal(const FrameDesc& frame, const FrameTime& time,
|
|||||||
|
|
||||||
CFrameTex * raw = new (std::nothrow) CFrameTex(core->graph, core->id,
|
CFrameTex * raw = new (std::nothrow) CFrameTex(core->graph, core->id,
|
||||||
core->node, m_index, m_version, core->profile, desc, time, resource,
|
core->node, m_index, m_version, core->profile, desc, time, resource,
|
||||||
sync, core->read, core->shared);
|
sync, core->read, core->shared, hold);
|
||||||
if (!raw)
|
if (!raw)
|
||||||
{
|
{
|
||||||
core->Drop(index, generation);
|
core->Drop(index, generation);
|
||||||
@@ -445,6 +448,13 @@ bool TexWrite::Seal(const FrameDesc& frame, const FrameTime& time,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TexWrite::Fail(const D12Sync& sync)
|
||||||
|
{
|
||||||
|
if (m_core)
|
||||||
|
m_core->Fail(m_index, m_version, sync);
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
void TexWrite::Cancel()
|
void TexWrite::Cancel()
|
||||||
{
|
{
|
||||||
if (m_core)
|
if (m_core)
|
||||||
|
|||||||
@@ -59,13 +59,15 @@ private:
|
|||||||
ComPtr<ID3D12Resource> m_res;
|
ComPtr<ID3D12Resource> m_res;
|
||||||
D12Sync m_sync;
|
D12Sync m_sync;
|
||||||
D3D12_RESOURCE_STATES m_state;
|
D3D12_RESOURCE_STATES m_state;
|
||||||
bool m_shared;
|
bool m_shared;
|
||||||
|
std::shared_ptr<void> m_hold;
|
||||||
|
|
||||||
CFrameTex(uint64_t graph, uint64_t pool, unsigned node, unsigned slot,
|
CFrameTex(uint64_t graph, uint64_t pool, unsigned node, unsigned slot,
|
||||||
uint64_t version, const FrameProfile& profile, const FrameDesc& frame,
|
uint64_t version, const FrameProfile& profile, const FrameDesc& frame,
|
||||||
const FrameTime& time, const ComPtr<ID3D12Resource>& res,
|
const FrameTime& time, const ComPtr<ID3D12Resource>& res,
|
||||||
const D12Sync& sync,
|
const D12Sync& sync,
|
||||||
D3D12_RESOURCE_STATES state, bool shared);
|
D3D12_RESOURCE_STATES state, bool shared,
|
||||||
|
const std::shared_ptr<void>& hold);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFrameTex(const CFrameTex&) = delete;
|
CFrameTex(const CFrameTex&) = delete;
|
||||||
@@ -141,15 +143,17 @@ public:
|
|||||||
// Seal only after producer commands restore the texture to the pool's
|
// Seal only after producer commands restore the texture to the pool's
|
||||||
// configured immutable state and Execute returns this exact sync point.
|
// configured immutable state and Execute returns this exact sync point.
|
||||||
bool Seal(const FrameDesc& frame, const FrameTime& time,
|
bool Seal(const FrameDesc& frame, const FrameTime& time,
|
||||||
const D12Sync& sync, TexLease& lease);
|
const D12Sync& sync, TexLease& lease,
|
||||||
|
const std::shared_ptr<void>& hold = {});
|
||||||
|
void Fail(const D12Sync& sync);
|
||||||
void Cancel();
|
void Cancel();
|
||||||
};
|
};
|
||||||
|
|
||||||
// One pool owns interchangeable textures for a single graph node. Reset stops
|
// One pool owns interchangeable textures for a single graph node. Reset stops
|
||||||
// acquisition and drains every sealed producer point. Existing writers and
|
// acquisition and drains every sealed producer point. Existing writers and
|
||||||
// leases keep the retired core alive. Reset invalidates writers; a writer
|
// leases keep the retired core alive. Reset invalidates writers; a writer
|
||||||
// which already submitted must still Seal so its point is safely drained,
|
// which already submitted must still Seal or Fail so its point is safely
|
||||||
// but it will not publish a product from the retired generation.
|
// drained, but it will not publish a product from the retired generation.
|
||||||
// The configured state is the promised state presented to every consumer;
|
// The configured state is the promised state presented to every consumer;
|
||||||
// it is not queried from D3D12. Consumers may read but never transition or
|
// it is not queried from D3D12. Consumers may read but never transition or
|
||||||
// write a shared product.
|
// write a shared product.
|
||||||
|
|||||||
@@ -161,6 +161,12 @@ bool CSwapChainProcessor::InitializePipeline()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_resPool.Init(m_dx11Device, m_dx12Device);
|
m_resPool.Init(m_dx11Device, m_dx12Device);
|
||||||
|
if (!m_exec.Init(m_dx11Device, m_dx12Device,
|
||||||
|
m_devContext->GetTransport().Tex()))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Failed to initialize the frame graph executor");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const bool enableEffects = !m_dx11Device->IsSoftware();
|
const bool enableEffects = !m_dx11Device->IsSoftware();
|
||||||
if (!enableEffects)
|
if (!enableEffects)
|
||||||
DEBUG_INFO("Software render adapter: post-processing disabled");
|
DEBUG_INFO("Software render adapter: post-processing disabled");
|
||||||
@@ -233,6 +239,7 @@ CSwapChainProcessor::~CSwapChainProcessor()
|
|||||||
// Drain in-flight GPU work / completion callbacks before releasing the
|
// Drain in-flight GPU work / completion callbacks before releasing the
|
||||||
// resources they reference. The swap chain was already released in the
|
// resources they reference. The swap chain was already released in the
|
||||||
// worker epilogue, so this does not hold an IddCx frame.
|
// worker epilogue, so this does not hold an IddCx frame.
|
||||||
|
m_exec.Reset();
|
||||||
if (m_dx12Device)
|
if (m_dx12Device)
|
||||||
{
|
{
|
||||||
m_dx12Device->WaitForIdle();
|
m_dx12Device->WaitForIdle();
|
||||||
@@ -565,7 +572,7 @@ void CSwapChainProcessor::CfgGraph()
|
|||||||
|
|
||||||
m_graphPending = false;
|
m_graphPending = false;
|
||||||
const CfgResult result =
|
const CfgResult result =
|
||||||
transport.Cfg(m_graphCfg, m_graphRev, m_graph);
|
transport.Cfg(m_graphCfg, m_graphRev, m_graph, &m_exec);
|
||||||
if (result == CfgResult::ACCEPTED)
|
if (result == CfgResult::ACCEPTED)
|
||||||
{
|
{
|
||||||
m_graphRetryAt = 0;
|
m_graphRetryAt = 0;
|
||||||
@@ -659,6 +666,8 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
|
|
||||||
D12FrameFormat srcFormat = {};
|
D12FrameFormat srcFormat = {};
|
||||||
srcFormat.desc = srcDesc;
|
srcFormat.desc = srcDesc;
|
||||||
|
srcFormat.dataWidth = (unsigned)srcDesc.Width;
|
||||||
|
srcFormat.dataHeight = srcDesc.Height;
|
||||||
srcFormat.width = (unsigned)srcDesc.Width;
|
srcFormat.width = (unsigned)srcDesc.Width;
|
||||||
srcFormat.height = srcDesc.Height;
|
srcFormat.height = srcDesc.Height;
|
||||||
srcFormat.format = D12::Type(srcDesc.Format);
|
srcFormat.format = D12::Type(srcDesc.Format);
|
||||||
@@ -825,6 +834,22 @@ bool CSwapChainProcessor::SwapChainNewFrame(ComPtr<IDXGIResource> acquiredBuffer
|
|||||||
if (needsReconfigure || postProcessFormatChanged || frameMetadataChanged)
|
if (needsReconfigure || postProcessFormatChanged || frameMetadataChanged)
|
||||||
m_transport.ForceFrame();
|
m_transport.ForceFrame();
|
||||||
|
|
||||||
|
const FrameDamage texDamage = noImageUpdate ? FrameDamage::NONE :
|
||||||
|
(fullDamage || !resolvedDirtyRectCount ?
|
||||||
|
FrameDamage::FULL : FrameDamage::RECTS);
|
||||||
|
const unsigned texRectCount = texDamage == FrameDamage::RECTS ?
|
||||||
|
resolvedDirtyRectCount : 0;
|
||||||
|
// This call is a no-op for the current legacy-only LGMP graph. When a
|
||||||
|
// texture route is selected, every read of the borrowed source is submitted
|
||||||
|
// here before FinishedProcessingFrame releases the IddCx surface.
|
||||||
|
const TexResult texResult = m_exec.Run(*srcRes, srcFormat, captureTime,
|
||||||
|
postProcessStart, texDamage, dirtyRects, texRectCount);
|
||||||
|
if (texResult == TexResult::FAILED && m_haveGraphCfg)
|
||||||
|
{
|
||||||
|
m_graphPending = true;
|
||||||
|
m_graphRetryAt = CFrameScheduler::Nanotime() + GRAPH_RETRY_NS;
|
||||||
|
}
|
||||||
|
|
||||||
const FrameSubmission submission =
|
const FrameSubmission submission =
|
||||||
{
|
{
|
||||||
srcRes,
|
srcRes,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "d3d/CD3D12Device.h"
|
#include "d3d/CD3D12Device.h"
|
||||||
#include "display/IddCxCompat.h"
|
#include "display/IddCxCompat.h"
|
||||||
#include "d3d/CInteropResourcePool.h"
|
#include "d3d/CInteropResourcePool.h"
|
||||||
|
#include "capture/CFrameExec.h"
|
||||||
#include "capture/CFrameGraph.h"
|
#include "capture/CFrameGraph.h"
|
||||||
#include "capture/CFrameProcessor.h"
|
#include "capture/CFrameProcessor.h"
|
||||||
#include "postprocess/D12FrameFormat.h"
|
#include "postprocess/D12FrameFormat.h"
|
||||||
@@ -57,6 +58,7 @@ private:
|
|||||||
HANDLE m_newFrameEvent;
|
HANDLE m_newFrameEvent;
|
||||||
|
|
||||||
CInteropResourcePool m_resPool;
|
CInteropResourcePool m_resPool;
|
||||||
|
CFrameExec m_exec;
|
||||||
CFrameGraph m_graph;
|
CFrameGraph m_graph;
|
||||||
GraphCfg m_graphCfg;
|
GraphCfg m_graphCfg;
|
||||||
bool m_haveGraphCfg = false;
|
bool m_haveGraphCfg = false;
|
||||||
|
|||||||
@@ -507,6 +507,21 @@ void CD3D12CommandQueue::DeInit()
|
|||||||
m_qpcFrequency = 0;
|
m_qpcFrequency = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CD3D12CommandSlot * CD3D12CommandQueue::Try(UINT slotIndex)
|
||||||
|
{
|
||||||
|
if (slotIndex >= m_slotCount)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
CD3D12CommandSlot& slot = m_slots[slotIndex];
|
||||||
|
if (slot.Acquire())
|
||||||
|
return &slot;
|
||||||
|
|
||||||
|
// The GPU may already be finished while its thread-pool callback is
|
||||||
|
// still pending. Complete it here without waiting for callback dispatch.
|
||||||
|
slot.OnCompletion(false);
|
||||||
|
return slot.Acquire() ? &slot : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
CD3D12CommandSlot * CD3D12CommandQueue::Acquire(UINT slotIndex)
|
CD3D12CommandSlot * CD3D12CommandQueue::Acquire(UINT slotIndex)
|
||||||
{
|
{
|
||||||
if (slotIndex >= m_slotCount)
|
if (slotIndex >= m_slotCount)
|
||||||
@@ -515,14 +530,8 @@ CD3D12CommandSlot * CD3D12CommandQueue::Acquire(UINT slotIndex)
|
|||||||
const ULONGLONG deadline = GetTickCount64() + 100;
|
const ULONGLONG deadline = GetTickCount64() + 100;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (m_slots[slotIndex].Acquire())
|
if (CD3D12CommandSlot * slot = Try(slotIndex))
|
||||||
return &m_slots[slotIndex];
|
return slot;
|
||||||
|
|
||||||
// The GPU may already be finished while its thread-pool callback is
|
|
||||||
// still pending. Complete it here before sleeping on callback dispatch.
|
|
||||||
m_slots[slotIndex].OnCompletion(false);
|
|
||||||
if (m_slots[slotIndex].Acquire())
|
|
||||||
return &m_slots[slotIndex];
|
|
||||||
if (Atomic::Load(m_failed, std::memory_order_acquire))
|
if (Atomic::Load(m_failed, std::memory_order_acquire))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -549,16 +558,7 @@ CD3D12CommandSlot * CD3D12CommandQueue::Acquire()
|
|||||||
// The unindexed path is used for immediate software publication. Keep at
|
// The unindexed path is used for immediate software publication. Keep at
|
||||||
// most one copy in flight so a newer frame is dropped instead of queued
|
// most one copy in flight so a newer frame is dropped instead of queued
|
||||||
// behind bandwidth-bound work which is already stale.
|
// behind bandwidth-bound work which is already stale.
|
||||||
CD3D12CommandSlot& slot = m_slots[0];
|
return Try(0);
|
||||||
if (slot.Acquire())
|
|
||||||
return &slot;
|
|
||||||
|
|
||||||
// Complete already-fenced work without waiting for callback dispatch.
|
|
||||||
slot.OnCompletion(false);
|
|
||||||
if (slot.Acquire())
|
|
||||||
return &slot;
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CD3D12CommandQueue::WaitForIdle()
|
void CD3D12CommandQueue::WaitForIdle()
|
||||||
|
|||||||
@@ -201,7 +201,12 @@ class CD3D12CommandQueue
|
|||||||
UINT slotCount, bool enableTiming = false, bool sharedFence = false);
|
UINT slotCount, bool enableTiming = false, bool sharedFence = false);
|
||||||
void DeInit();
|
void DeInit();
|
||||||
|
|
||||||
|
CD3D12CommandSlot * Try(UINT slotIndex);
|
||||||
CD3D12CommandSlot * Acquire(UINT slotIndex);
|
CD3D12CommandSlot * Acquire(UINT slotIndex);
|
||||||
CD3D12CommandSlot * Acquire();
|
CD3D12CommandSlot * Acquire();
|
||||||
|
bool Failed() const
|
||||||
|
{
|
||||||
|
return Atomic::Load(m_failed, std::memory_order_acquire);
|
||||||
|
}
|
||||||
void WaitForIdle();
|
void WaitForIdle();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -165,6 +165,20 @@ bool CColorTransformEffect::Init(const ComPtr<ID3D12Device3>& device)
|
|||||||
PostProcessStatus CColorTransformEffect::SetFormat(
|
PostProcessStatus CColorTransformEffect::SetFormat(
|
||||||
const ComPtr<ID3D12Device3>& device,
|
const ComPtr<ID3D12Device3>& device,
|
||||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Set(device, src, dst, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CColorTransformEffect::Cfg(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Set(device, src, dst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CColorTransformEffect::Set(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst, bool own)
|
||||||
{
|
{
|
||||||
const auto transform = D12::Transform(src.colorTransform);
|
const auto transform = D12::Transform(src.colorTransform);
|
||||||
if (!transform)
|
if (!transform)
|
||||||
@@ -205,10 +219,15 @@ PostProcessStatus CColorTransformEffect::SetFormat(
|
|||||||
|
|
||||||
D3D12_RESOURCE_DESC desc = src.desc;
|
D3D12_RESOURCE_DESC desc = src.desc;
|
||||||
desc.Format = dstFormat;
|
desc.Format = dstFormat;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
desc.Flags = own ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS :
|
||||||
if (!m_dst || m_dst->GetDesc().Width != desc.Width ||
|
dst.desc.Flags;
|
||||||
m_dst->GetDesc().Height != desc.Height ||
|
if (!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS))
|
||||||
m_dst->GetDesc().Format != desc.Format)
|
return PostProcessStatus::FAILED;
|
||||||
|
if (own &&
|
||||||
|
(!m_dst ||
|
||||||
|
m_dst->GetDesc().Width != desc.Width ||
|
||||||
|
m_dst->GetDesc().Height != desc.Height ||
|
||||||
|
m_dst->GetDesc().Format != desc.Format))
|
||||||
{
|
{
|
||||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
if (!CreateDefaultTexture(device, desc, m_dst))
|
||||||
return PostProcessStatus::FAILED;
|
return PostProcessStatus::FAILED;
|
||||||
@@ -216,9 +235,9 @@ PostProcessStatus CColorTransformEffect::SetFormat(
|
|||||||
|
|
||||||
std::memcpy(m_consts.matrix, transform->matrix,
|
std::memcpy(m_consts.matrix, transform->matrix,
|
||||||
sizeof(m_consts.matrix));
|
sizeof(m_consts.matrix));
|
||||||
m_consts.scalar = transform->scalar;
|
m_consts.scalar = transform->scalar;
|
||||||
m_consts.matrixEnabled = matrixEnabled;
|
m_consts.matrixEnabled = matrixEnabled;
|
||||||
m_consts.lutEnabled = lutEnabled;
|
m_consts.lutEnabled = lutEnabled;
|
||||||
const UINT inputTransfer = src.hdrPQ ? TRANSFER_PQ :
|
const UINT inputTransfer = src.hdrPQ ? TRANSFER_PQ :
|
||||||
(src.hdr ? TRANSFER_LINEAR : TRANSFER_SRGB);
|
(src.hdr ? TRANSFER_LINEAR : TRANSFER_SRGB);
|
||||||
m_consts.inputTransfer = inputTransfer;
|
m_consts.inputTransfer = inputTransfer;
|
||||||
@@ -230,6 +249,7 @@ PostProcessStatus CColorTransformEffect::SetFormat(
|
|||||||
|
|
||||||
m_srcFormat = src.desc.Format;
|
m_srcFormat = src.desc.Format;
|
||||||
m_dstFormat = dstFormat;
|
m_dstFormat = dstFormat;
|
||||||
|
m_outDesc = desc;
|
||||||
m_threadsX = Groups((unsigned)desc.Width);
|
m_threadsX = Groups((unsigned)desc.Width);
|
||||||
m_threadsY = Groups(desc.Height);
|
m_threadsY = Groups(desc.Height);
|
||||||
|
|
||||||
@@ -245,6 +265,30 @@ ComPtr<ID3D12Resource> CColorTransformEffect::Run(
|
|||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
unsigned * nbDirtyRects)
|
unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!m_dst || !Draw(device, commandList, src, m_dst.Get(),
|
||||||
|
dirtyRects, nbDirtyRects))
|
||||||
|
return nullptr;
|
||||||
|
return m_dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CColorTransformEffect::Run(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!device || !commandList || !src || src.Get() == dst || !IsDst(dst))
|
||||||
|
return false;
|
||||||
|
return Draw(device, commandList, src, dst,
|
||||||
|
dirtyRects, nbDirtyRects);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CColorTransformEffect::Draw(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(dirtyRects);
|
UNREFERENCED_PARAMETER(dirtyRects);
|
||||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||||
@@ -261,7 +305,7 @@ ComPtr<ID3D12Resource> CColorTransformEffect::Run(
|
|||||||
m_uploadPending = false;
|
m_uploadPending = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_COMMON,
|
||||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||||
|
|
||||||
CBV(device, 0, m_constBuffer.Get(), sizeof(m_consts));
|
CBV(device, 0, m_constBuffer.Get(), sizeof(m_consts));
|
||||||
@@ -275,10 +319,10 @@ ComPtr<ID3D12Resource> CColorTransformEffect::Run(
|
|||||||
device->CreateShaderResourceView(
|
device->CreateShaderResourceView(
|
||||||
m_lutBuffer.Get(), &lutDesc, Handle(device, 2));
|
m_lutBuffer.Get(), &lutDesc, Handle(device, 2));
|
||||||
|
|
||||||
UAV(device, 3, m_dst.Get(), m_dstFormat);
|
UAV(device, 3, dst, m_dstFormat);
|
||||||
Dispatch(commandList);
|
Dispatch(commandList);
|
||||||
|
|
||||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||||
D3D12_RESOURCE_STATE_COMMON);
|
D3D12_RESOURCE_STATE_COMMON);
|
||||||
return m_dst;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,13 @@ private:
|
|||||||
CalPart m_part;
|
CalPart m_part;
|
||||||
bool m_keepSignal;
|
bool m_keepSignal;
|
||||||
|
|
||||||
|
PostProcessStatus Set(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst, bool own);
|
||||||
|
bool Draw(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CColorTransformEffect(CalPart part = CalPart::ALL,
|
explicit CColorTransformEffect(CalPart part = CalPart::ALL,
|
||||||
bool keepSignal = false) :
|
bool keepSignal = false) :
|
||||||
@@ -62,9 +69,17 @@ public:
|
|||||||
|
|
||||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||||
|
// Configures shader state without allocating the legacy-owned output.
|
||||||
|
PostProcessStatus Cfg(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst);
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
unsigned * nbDirtyRects) override;
|
unsigned * nbDirtyRects) override;
|
||||||
|
// dst must match Cfg's output and be in COMMON; Run restores COMMON.
|
||||||
|
bool Run(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -280,11 +280,27 @@ void CComputeEffect::UAV(const ComPtr<ID3D12Device3>& device, UINT index,
|
|||||||
void CComputeEffect::TransitionDst(
|
void CComputeEffect::TransitionDst(
|
||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
|
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after)
|
||||||
|
{
|
||||||
|
TransitionDst(commandList, m_dst.Get(), before, after);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CComputeEffect::IsDst(ID3D12Resource * dst) const
|
||||||
|
{
|
||||||
|
if (!dst)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return D12::Same(dst->GetDesc(), m_outDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CComputeEffect::TransitionDst(
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
ID3D12Resource * dst, D3D12_RESOURCE_STATES before,
|
||||||
|
D3D12_RESOURCE_STATES after)
|
||||||
{
|
{
|
||||||
D3D12_RESOURCE_BARRIER barrier = {};
|
D3D12_RESOURCE_BARRIER barrier = {};
|
||||||
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
|
||||||
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
|
||||||
barrier.Transition.pResource = m_dst.Get();
|
barrier.Transition.pResource = dst;
|
||||||
barrier.Transition.StateBefore = before;
|
barrier.Transition.StateBefore = before;
|
||||||
barrier.Transition.StateAfter = after;
|
barrier.Transition.StateAfter = after;
|
||||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ protected:
|
|||||||
ComPtr<ID3D12PipelineState> m_pso;
|
ComPtr<ID3D12PipelineState> m_pso;
|
||||||
ComPtr<ID3D12DescriptorHeap> m_descHeap;
|
ComPtr<ID3D12DescriptorHeap> m_descHeap;
|
||||||
ComPtr<ID3D12Resource> m_dst;
|
ComPtr<ID3D12Resource> m_dst;
|
||||||
|
D3D12_RESOURCE_DESC m_outDesc = {};
|
||||||
unsigned m_threadsX = 0;
|
unsigned m_threadsX = 0;
|
||||||
unsigned m_threadsY = 0;
|
unsigned m_threadsY = 0;
|
||||||
|
|
||||||
@@ -81,6 +82,11 @@ protected:
|
|||||||
void UAV(const ComPtr<ID3D12Device3>& device, UINT index,
|
void UAV(const ComPtr<ID3D12Device3>& device, UINT index,
|
||||||
ID3D12Resource * resource, DXGI_FORMAT format) const;
|
ID3D12Resource * resource, DXGI_FORMAT format) const;
|
||||||
|
|
||||||
|
bool IsDst(ID3D12Resource * dst) const;
|
||||||
|
|
||||||
void TransitionDst(const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
void TransitionDst(const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after);
|
D3D12_RESOURCE_STATES before, D3D12_RESOURCE_STATES after);
|
||||||
|
void TransitionDst(const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
ID3D12Resource * dst, D3D12_RESOURCE_STATES before,
|
||||||
|
D3D12_RESOURCE_STATES after);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -156,6 +156,20 @@ bool CDownsampleEffect::Init(const ComPtr<ID3D12Device3>& device, bool report)
|
|||||||
PostProcessStatus CDownsampleEffect::SetFormat(
|
PostProcessStatus CDownsampleEffect::SetFormat(
|
||||||
const ComPtr<ID3D12Device3>& device,
|
const ComPtr<ID3D12Device3>& device,
|
||||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Set(device, src, dst, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CDownsampleEffect::Cfg(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Set(device, src, dst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CDownsampleEffect::Set(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst, bool own)
|
||||||
{
|
{
|
||||||
unsigned targetX = m_targetX;
|
unsigned targetX = m_targetX;
|
||||||
unsigned targetY = m_targetY;
|
unsigned targetY = m_targetY;
|
||||||
@@ -174,9 +188,12 @@ PostProcessStatus CDownsampleEffect::SetFormat(
|
|||||||
D3D12_RESOURCE_DESC desc = src.desc;
|
D3D12_RESOURCE_DESC desc = src.desc;
|
||||||
desc.Width = targetX;
|
desc.Width = targetX;
|
||||||
desc.Height = targetY;
|
desc.Height = targetY;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
desc.Flags = own ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS :
|
||||||
|
dst.desc.Flags;
|
||||||
|
if (!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS))
|
||||||
|
return PostProcessStatus::FAILED;
|
||||||
|
|
||||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
if (own && !CreateDefaultTexture(device, desc, m_dst))
|
||||||
return PostProcessStatus::FAILED;
|
return PostProcessStatus::FAILED;
|
||||||
|
|
||||||
m_consts.width = (float)targetX;
|
m_consts.width = (float)targetX;
|
||||||
@@ -190,6 +207,7 @@ PostProcessStatus CDownsampleEffect::SetFormat(
|
|||||||
}
|
}
|
||||||
m_threadsX = Groups((unsigned)desc.Width);
|
m_threadsX = Groups((unsigned)desc.Width);
|
||||||
m_threadsY = Groups(desc.Height);
|
m_threadsY = Groups(desc.Height);
|
||||||
|
m_outDesc = desc;
|
||||||
m_format = src.desc.Format;
|
m_format = src.desc.Format;
|
||||||
m_scaleX = (double)desc.Width / src.desc.Width;
|
m_scaleX = (double)desc.Width / src.desc.Width;
|
||||||
m_scaleY = (double)desc.Height / src.desc.Height;
|
m_scaleY = (double)desc.Height / src.desc.Height;
|
||||||
@@ -225,19 +243,43 @@ ComPtr<ID3D12Resource> CDownsampleEffect::Run(
|
|||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
unsigned * nbDirtyRects)
|
unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!m_dst || !Draw(device, commandList, src, m_dst.Get(),
|
||||||
|
dirtyRects, nbDirtyRects))
|
||||||
|
return nullptr;
|
||||||
|
return m_dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDownsampleEffect::Run(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!device || !commandList || !src || src.Get() == dst || !IsDst(dst))
|
||||||
|
return false;
|
||||||
|
return Draw(device, commandList, src, dst,
|
||||||
|
dirtyRects, nbDirtyRects);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDownsampleEffect::Draw(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(dirtyRects);
|
UNREFERENCED_PARAMETER(dirtyRects);
|
||||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||||
|
|
||||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_COMMON,
|
||||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||||
|
|
||||||
CBV(device, 0, m_constBuffer.Get(), sizeof(m_consts));
|
CBV(device, 0, m_constBuffer.Get(), sizeof(m_consts));
|
||||||
SRV(device, 1, src.Get(), m_format);
|
SRV(device, 1, src.Get(), m_format);
|
||||||
UAV(device, 2, m_dst.Get(), m_format);
|
UAV(device, 2, dst, m_format);
|
||||||
Dispatch(commandList);
|
Dispatch(commandList);
|
||||||
|
|
||||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||||
D3D12_RESOURCE_STATE_COMMON);
|
D3D12_RESOURCE_STATE_COMMON);
|
||||||
return m_dst;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ private:
|
|||||||
|
|
||||||
bool ParseRules(const std::wstring& value, bool report);
|
bool ParseRules(const std::wstring& value, bool report);
|
||||||
const Rule * MatchRule(unsigned width, unsigned height) const;
|
const Rule * MatchRule(unsigned width, unsigned height) const;
|
||||||
|
PostProcessStatus Set(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst, bool own);
|
||||||
|
bool Draw(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CDownsampleEffect() = default;
|
CDownsampleEffect() = default;
|
||||||
@@ -67,6 +73,9 @@ public:
|
|||||||
|
|
||||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||||
|
// Configures shader state without allocating the legacy-owned output.
|
||||||
|
PostProcessStatus Cfg(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst);
|
||||||
|
|
||||||
void AdjustDamage(RECT dirtyRects[], unsigned * nbDirtyRects) override;
|
void AdjustDamage(RECT dirtyRects[], unsigned * nbDirtyRects) override;
|
||||||
|
|
||||||
@@ -74,4 +83,9 @@ public:
|
|||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
unsigned * nbDirtyRects) override;
|
unsigned * nbDirtyRects) override;
|
||||||
|
// dst must match Cfg's output and be in COMMON; Run restores COMMON.
|
||||||
|
bool Run(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
};
|
};
|
||||||
|
|||||||
164
idd/LGIdd/postprocess/effect/CFormatEffect.cpp
Normal file
164
idd/LGIdd/postprocess/effect/CFormatEffect.cpp
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "CFormatEffect.h"
|
||||||
|
|
||||||
|
#include "CDebug.h"
|
||||||
|
|
||||||
|
using namespace PostProcessUtil;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
bool IsSDR8(const D12FrameFormat& format)
|
||||||
|
{
|
||||||
|
if (format.hdr || format.hdrPQ)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (format.format)
|
||||||
|
{
|
||||||
|
case FRAME_TYPE_BGRA:
|
||||||
|
return format.desc.Format == DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
case FRAME_TYPE_RGBA:
|
||||||
|
return format.desc.Format == DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFormatEffect::Init(const ComPtr<ID3D12Device3>& device)
|
||||||
|
{
|
||||||
|
D3D12_DESCRIPTOR_RANGE ranges[] =
|
||||||
|
{
|
||||||
|
Range(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0),
|
||||||
|
Range(D3D12_DESCRIPTOR_RANGE_TYPE_UAV, 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
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"
|
||||||
|
" dst[dt.xy] = src[dt.xy];\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
return InitCompute(device, ranges, ARRAYSIZE(ranges), nullptr, 0, shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CFormatEffect::SetFormat(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Cfg(device, src, dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CFormatEffect::Cfg(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, const D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(device);
|
||||||
|
|
||||||
|
if (src.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||||
|
dst.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D ||
|
||||||
|
!src.desc.Width ||
|
||||||
|
!src.desc.Height ||
|
||||||
|
src.desc.Width != dst.desc.Width ||
|
||||||
|
src.desc.Height != dst.desc.Height ||
|
||||||
|
!IsSDR8(src) ||
|
||||||
|
!IsSDR8(dst))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Unsupported texture format conversion");
|
||||||
|
return PostProcessStatus::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src.desc.Format == dst.desc.Format)
|
||||||
|
return PostProcessStatus::BYPASS_EFFECT;
|
||||||
|
|
||||||
|
if (!(dst.desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS))
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Format conversion destination does not allow UAV access");
|
||||||
|
return PostProcessStatus::FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_srcDesc = src.desc;
|
||||||
|
m_outDesc = dst.desc;
|
||||||
|
m_srcFormat = src.desc.Format;
|
||||||
|
m_dstFormat = dst.desc.Format;
|
||||||
|
m_threadsX = Groups((unsigned)dst.desc.Width);
|
||||||
|
m_threadsY = Groups(dst.desc.Height);
|
||||||
|
return PostProcessStatus::SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComPtr<ID3D12Resource> CFormatEffect::Run(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
|
unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(device);
|
||||||
|
UNREFERENCED_PARAMETER(commandList);
|
||||||
|
UNREFERENCED_PARAMETER(src);
|
||||||
|
UNREFERENCED_PARAMETER(dirtyRects);
|
||||||
|
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFormatEffect::IsSrc(ID3D12Resource * src) const
|
||||||
|
{
|
||||||
|
if (!src)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return D12::Same(src->GetDesc(), m_srcDesc, D12::DescCmp::VIEW);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFormatEffect::Run(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!device || !commandList || !IsSrc(src.Get()) ||
|
||||||
|
src.Get() == dst || !IsDst(dst))
|
||||||
|
return false;
|
||||||
|
return Draw(device, commandList, src, dst, dirtyRects, nbDirtyRects);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFormatEffect::Draw(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(dirtyRects);
|
||||||
|
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||||
|
|
||||||
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_COMMON,
|
||||||
|
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||||
|
|
||||||
|
SRV(device, 0, src.Get(), m_srcFormat);
|
||||||
|
UAV(device, 1, dst, m_dstFormat);
|
||||||
|
Dispatch(commandList);
|
||||||
|
|
||||||
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||||
|
D3D12_RESOURCE_STATE_COMMON);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
57
idd/LGIdd/postprocess/effect/CFormatEffect.h
Normal file
57
idd/LGIdd/postprocess/effect/CFormatEffect.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CComputeEffect.h"
|
||||||
|
|
||||||
|
class CFormatEffect : public CComputeEffect
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
D3D12_RESOURCE_DESC m_srcDesc = {};
|
||||||
|
DXGI_FORMAT m_srcFormat = DXGI_FORMAT_UNKNOWN;
|
||||||
|
DXGI_FORMAT m_dstFormat = DXGI_FORMAT_UNKNOWN;
|
||||||
|
|
||||||
|
bool IsSrc(ID3D12Resource * src) const;
|
||||||
|
bool Draw(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const char * GetName() const override { return "Format"; }
|
||||||
|
|
||||||
|
bool Init(const ComPtr<ID3D12Device3>& device);
|
||||||
|
|
||||||
|
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||||
|
PostProcessStatus Cfg(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, const D12FrameFormat& dst);
|
||||||
|
|
||||||
|
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
|
unsigned * nbDirtyRects) override;
|
||||||
|
// dst must match Cfg's output and be in COMMON; Run restores COMMON.
|
||||||
|
bool Run(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
|
};
|
||||||
@@ -87,17 +87,35 @@ bool CHDR16to10Effect::Init(const ComPtr<ID3D12Device3>& device)
|
|||||||
PostProcessStatus CHDR16to10Effect::SetFormat(
|
PostProcessStatus CHDR16to10Effect::SetFormat(
|
||||||
const ComPtr<ID3D12Device3>& device,
|
const ComPtr<ID3D12Device3>& device,
|
||||||
const D12FrameFormat& src, D12FrameFormat& dst)
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Set(device, src, dst, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CHDR16to10Effect::Cfg(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst)
|
||||||
|
{
|
||||||
|
return Set(device, src, dst, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PostProcessStatus CHDR16to10Effect::Set(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst, bool own)
|
||||||
{
|
{
|
||||||
if (src.desc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT || !src.hdr)
|
if (src.desc.Format != DXGI_FORMAT_R16G16B16A16_FLOAT || !src.hdr)
|
||||||
return PostProcessStatus::BYPASS_EFFECT;
|
return PostProcessStatus::BYPASS_EFFECT;
|
||||||
|
|
||||||
D3D12_RESOURCE_DESC desc = src.desc;
|
D3D12_RESOURCE_DESC desc = src.desc;
|
||||||
desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
|
desc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
|
||||||
desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
desc.Flags = own ? D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS :
|
||||||
|
dst.desc.Flags;
|
||||||
if (!CreateDefaultTexture(device, desc, m_dst))
|
if (!(desc.Flags & D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS))
|
||||||
return PostProcessStatus::FAILED;
|
return PostProcessStatus::FAILED;
|
||||||
|
|
||||||
|
if (own && !CreateDefaultTexture(device, desc, m_dst))
|
||||||
|
return PostProcessStatus::FAILED;
|
||||||
|
|
||||||
|
m_outDesc = desc;
|
||||||
m_threadsX = Groups((unsigned)desc.Width);
|
m_threadsX = Groups((unsigned)desc.Width);
|
||||||
m_threadsY = Groups(desc.Height);
|
m_threadsY = Groups(desc.Height);
|
||||||
|
|
||||||
@@ -118,19 +136,43 @@ ComPtr<ID3D12Resource> CHDR16to10Effect::Run(
|
|||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
unsigned * nbDirtyRects)
|
unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!m_dst || !Draw(device, commandList, src, m_dst.Get(),
|
||||||
|
dirtyRects, nbDirtyRects))
|
||||||
|
return nullptr;
|
||||||
|
return m_dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHDR16to10Effect::Run(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
|
{
|
||||||
|
if (!device || !commandList || !src || src.Get() == dst || !IsDst(dst))
|
||||||
|
return false;
|
||||||
|
return Draw(device, commandList, src, dst,
|
||||||
|
dirtyRects, nbDirtyRects);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CHDR16to10Effect::Draw(
|
||||||
|
const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects)
|
||||||
{
|
{
|
||||||
UNREFERENCED_PARAMETER(dirtyRects);
|
UNREFERENCED_PARAMETER(dirtyRects);
|
||||||
UNREFERENCED_PARAMETER(nbDirtyRects);
|
UNREFERENCED_PARAMETER(nbDirtyRects);
|
||||||
|
|
||||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_COMMON,
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_COMMON,
|
||||||
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||||
|
|
||||||
CBV(device, 0, m_constBuffer.Get(), sizeof(m_consts));
|
CBV(device, 0, m_constBuffer.Get(), sizeof(m_consts));
|
||||||
SRV(device, 1, src.Get(), DXGI_FORMAT_R16G16B16A16_FLOAT);
|
SRV(device, 1, src.Get(), DXGI_FORMAT_R16G16B16A16_FLOAT);
|
||||||
UAV(device, 2, m_dst.Get(), DXGI_FORMAT_R10G10B10A2_UNORM);
|
UAV(device, 2, dst, DXGI_FORMAT_R10G10B10A2_UNORM);
|
||||||
Dispatch(commandList);
|
Dispatch(commandList);
|
||||||
|
|
||||||
TransitionDst(commandList, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
TransitionDst(commandList, dst, D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
|
||||||
D3D12_RESOURCE_STATE_COMMON);
|
D3D12_RESOURCE_STATE_COMMON);
|
||||||
return m_dst;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,13 @@ private:
|
|||||||
} m_consts = { 80.0f };
|
} m_consts = { 80.0f };
|
||||||
ComPtr<ID3D12Resource> m_constBuffer;
|
ComPtr<ID3D12Resource> m_constBuffer;
|
||||||
|
|
||||||
|
PostProcessStatus Set(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst, bool own);
|
||||||
|
bool Draw(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const char * GetName() const override { return "HDR16to10"; }
|
const char * GetName() const override { return "HDR16to10"; }
|
||||||
|
|
||||||
@@ -38,9 +45,17 @@ public:
|
|||||||
|
|
||||||
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
PostProcessStatus SetFormat(const ComPtr<ID3D12Device3>& device,
|
||||||
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
const D12FrameFormat& src, D12FrameFormat& dst) override;
|
||||||
|
// Configures shader state without allocating the legacy-owned output.
|
||||||
|
PostProcessStatus Cfg(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const D12FrameFormat& src, D12FrameFormat& dst);
|
||||||
|
|
||||||
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
ComPtr<ID3D12Resource> Run(const ComPtr<ID3D12Device3>& device,
|
||||||
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
|
||||||
unsigned * nbDirtyRects) override;
|
unsigned * nbDirtyRects) override;
|
||||||
|
// dst must match Cfg's output and be in COMMON; Run restores COMMON.
|
||||||
|
bool Run(const ComPtr<ID3D12Device3>& device,
|
||||||
|
const ComPtr<ID3D12GraphicsCommandList>& commandList,
|
||||||
|
const ComPtr<ID3D12Resource>& src, ID3D12Resource * dst,
|
||||||
|
RECT dirtyRects[], unsigned * nbDirtyRects);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -490,6 +490,24 @@ void CTexHub::Abort(CTexStage& stage) noexcept
|
|||||||
drop.reset();
|
drop.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CTexHub::Fault(
|
||||||
|
const FrameIn& frame, PushResult result) noexcept
|
||||||
|
{
|
||||||
|
if (result != PushResult::REJECTED && result != PushResult::FAILED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::shared_ptr<CTexSet> set;
|
||||||
|
unsigned index;
|
||||||
|
ITexSink * sink = nullptr;
|
||||||
|
if (!Enter(frame, true, set, index, sink))
|
||||||
|
{
|
||||||
|
if (set)
|
||||||
|
Leave(set, TRANSPORT_MAX_INSTANCES);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Finish(set, index, result);
|
||||||
|
}
|
||||||
|
|
||||||
PushResult CTexHub::Push(FrameIn frame, TexLease lease) noexcept
|
PushResult CTexHub::Push(FrameIn frame, TexLease lease) noexcept
|
||||||
{
|
{
|
||||||
std::shared_ptr<CTexSet> set;
|
std::shared_ptr<CTexSet> set;
|
||||||
|
|||||||
@@ -90,19 +90,18 @@ private:
|
|||||||
std::shared_ptr<CTexSet> m_active;
|
std::shared_ptr<CTexSet> m_active;
|
||||||
std::shared_ptr<CTexSet> m_pending;
|
std::shared_ptr<CTexSet> m_pending;
|
||||||
std::atomic<uint64_t> & m_rev;
|
std::atomic<uint64_t> & m_rev;
|
||||||
HANDLE m_idle = nullptr;
|
HANDLE m_idle = nullptr;
|
||||||
unsigned m_calls = 0;
|
unsigned m_calls = 0;
|
||||||
bool m_open = true;
|
bool m_open = true;
|
||||||
bool m_changing = false;
|
bool m_changing = false;
|
||||||
bool m_stopped = false;
|
bool m_stopped = false;
|
||||||
FaultRec m_faults[MAX_FAULTS] = {};
|
FaultRec m_faults[MAX_FAULTS] = {};
|
||||||
unsigned m_faultCount = 0;
|
unsigned m_faultCount = 0;
|
||||||
Failure m_failures[TRANSPORT_MAX_INSTANCES] = {};
|
Failure m_failures[TRANSPORT_MAX_INSTANCES] = {};
|
||||||
unsigned m_failureCount = 0;
|
unsigned m_failureCount = 0;
|
||||||
|
|
||||||
static bool Match(const FaultRec& fault, BackendId id, uint32_t epoch,
|
static bool Match(const FaultRec& fault, BackendId id, uint32_t epoch,
|
||||||
const FrameCfg& cfg, bool anyCfg = false);
|
const FrameCfg& cfg, bool anyCfg = false);
|
||||||
|
|
||||||
bool Enter(const FrameIn& frame, bool lease,
|
bool Enter(const FrameIn& frame, bool lease,
|
||||||
std::shared_ptr<CTexSet>& set, unsigned& route, ITexSink *& sink);
|
std::shared_ptr<CTexSet>& set, unsigned& route, ITexSink *& sink);
|
||||||
void Finish(const std::shared_ptr<CTexSet>& set, unsigned route,
|
void Finish(const std::shared_ptr<CTexSet>& set, unsigned route,
|
||||||
@@ -135,6 +134,7 @@ private:
|
|||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void Fault(const FrameIn& frame, PushResult result) noexcept;
|
||||||
PushResult Push(FrameIn frame, TexLease lease) noexcept;
|
PushResult Push(FrameIn frame, TexLease lease) noexcept;
|
||||||
PushResult Push(FrameIn frame, D11Lease lease) noexcept;
|
PushResult Push(FrameIn frame, D11Lease lease) noexcept;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -809,15 +809,15 @@ void CTransportManager::RetryEntry(Entry& entry, uint64_t now,
|
|||||||
const bool frameService =
|
const bool frameService =
|
||||||
(entry.config.services & TRANSPORT_SERVICE_FRAME) != 0;
|
(entry.config.services & TRANSPORT_SERVICE_FRAME) != 0;
|
||||||
entry.transport.reset();
|
entry.transport.reset();
|
||||||
entry.directMemory = DirectFrameBufferMemory {};
|
entry.directMemory = DirectFrameBufferMemory {};
|
||||||
entry.directMemoryValid = false;
|
entry.directMemoryValid = false;
|
||||||
entry.setupDone = false;
|
entry.setupDone = false;
|
||||||
entry.controlFailed = false;
|
entry.controlFailed = false;
|
||||||
entry.controlAbsent = false;
|
entry.controlAbsent = false;
|
||||||
entry.inputFailed = false;
|
entry.inputFailed = false;
|
||||||
entry.inputAbsent = false;
|
entry.inputAbsent = false;
|
||||||
entry.frameAbsent = false;
|
entry.frameAbsent = false;
|
||||||
entry.serviceRetryAt = 0;
|
entry.serviceRetryAt = 0;
|
||||||
Seq::Inc(entry.epoch);
|
Seq::Inc(entry.epoch);
|
||||||
if (frameService)
|
if (frameService)
|
||||||
BumpFrameRev();
|
BumpFrameRev();
|
||||||
@@ -1254,7 +1254,7 @@ CfgResult CTransportManager::Cfg(const GraphCfg& cfg,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (!next.Add(route.id, route.epoch, route.required,
|
if (!next.Add(route.id, route.epoch, route.required,
|
||||||
route.primary, candidate))
|
route.primary, route.texSink != nullptr, candidate))
|
||||||
{
|
{
|
||||||
route.transport->Abort();
|
route.transport->Abort();
|
||||||
routeResult = CfgResult::FAILED;
|
routeResult = CfgResult::FAILED;
|
||||||
|
|||||||
Reference in New Issue
Block a user