[idd] project: organize driver sources by responsibility

Group the IDD sources and Visual Studio filters by subsystem.

Split the device and swap-chain implementations into focused units,
rename the context classes, and reduce header coupling.
This commit is contained in:
Geoffrey McRae
2026-08-07 14:38:36 +10:00
parent 3ddc199bec
commit 30a1383d5e
76 changed files with 5067 additions and 3923 deletions

View File

@@ -0,0 +1,484 @@
/**
* 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 "postprocess/CPostProcessor.h"
#include "d3d/CD3D12Device.h"
#include "CDebug.h"
#include "postprocess/effect/CColorTransformEffect.h"
#include "postprocess/effect/CDownsampleEffect.h"
#include "postprocess/effect/CHDR16to10Effect.h"
#include "postprocess/effect/CRGB24Effect.h"
#include <cstring>
#include <limits>
#include <utility>
namespace
{
bool NearlyEqual(float a, float b, float tolerance)
{
const float delta = a - b;
return delta >= -tolerance && delta <= tolerance;
}
}
bool IsIdentityColorTransform(const D12ColorTransform& transform)
{
static const float matrixTolerance = 1.0f / 1048576.0f;
static const float lutTolerance = 1.0f / 65535.0f;
if (transform.matrixEnabled)
{
for (unsigned row = 0; row < 3; ++row)
for (unsigned column = 0; column < 4; ++column)
{
const float expected = row == column ? 1.0f : 0.0f;
const float effective =
transform.matrix[row][column] * transform.scalar;
if (!NearlyEqual(effective, expected, matrixTolerance))
return false;
}
}
if (transform.lutEnabled)
for (unsigned i = 0; i < 4096; ++i)
{
const float expected = (float)i / 4095.0f;
if (!NearlyEqual(transform.lut[i][0], expected, lutTolerance) ||
!NearlyEqual(transform.lut[i][1], expected, lutTolerance) ||
!NearlyEqual(transform.lut[i][2], expected, lutTolerance))
return false;
}
return true;
}
static void CopyHDRMetadata(D12FrameFormat& dst, const D12FrameFormat& src)
{
dst.hdrMetadata = src.hdrMetadata;
dst.sdrWhiteLevel = src.sdrWhiteLevel;
std::memcpy(dst.displayPrimary, src.displayPrimary, sizeof(dst.displayPrimary));
std::memcpy(dst.whitePoint, src.whitePoint, sizeof(dst.whitePoint));
dst.maxDisplayLuminance = src.maxDisplayLuminance;
dst.minDisplayLuminance = src.minDisplayLuminance;
dst.maxContentLightLevel = src.maxContentLightLevel;
dst.maxFrameAverageLightLevel = src.maxFrameAverageLightLevel;
}
bool CPostProcessor::Init(std::shared_ptr<CD3D12Device> dx12Device,
bool enableEffects)
{
m_dx12Device = dx12Device;
m_device = dx12Device->GetDevice();
m_effects.clear();
if (!enableEffects)
return true;
std::unique_ptr<CColorTransformEffect> colorTransform(new CColorTransformEffect());
if (colorTransform->Init(m_device))
{
DEBUG_INFO("Created post-processing effect: %s", colorTransform->GetName());
m_effects.push_back(std::move(colorTransform));
}
else
return false;
std::unique_ptr<CDownsampleEffect> downsample(new CDownsampleEffect());
if (downsample->Init(m_device))
{
DEBUG_INFO("Created post-processing effect: %s", downsample->GetName());
m_effects.push_back(std::move(downsample));
}
std::unique_ptr<CHDR16to10Effect> hdr16to10(new CHDR16to10Effect());
if (hdr16to10->Init(m_device))
{
DEBUG_INFO("Created post-processing effect: %s", hdr16to10->GetName());
m_effects.push_back(std::move(hdr16to10));
}
else
return false;
std::unique_ptr<CRGB24Effect> rgb24(new CRGB24Effect());
if (rgb24->Init(m_device))
{
DEBUG_INFO("Created post-processing effect: %s", rgb24->GetName());
m_effects.push_back(std::move(rgb24));
}
return true;
}
void CPostProcessor::Reset()
{
m_effects.clear();
m_dx12Device.reset();
m_device.Reset();
m_srcFormat = {};
m_dstFormat = {};
m_copyLayout = {};
m_copyEffect = nullptr;
m_frameSize = 0;
m_pitch = 0;
m_effectsActive = false;
m_configured = false;
}
bool CPostProcessor::HasSameEffectChain(const CPostProcessor& other) const
{
if (m_effects.size() != other.m_effects.size())
return false;
for (size_t i = 0; i < m_effects.size(); ++i)
if (std::strcmp(m_effects[i]->GetName(),
other.m_effects[i]->GetName()) != 0)
return false;
return true;
}
bool CPostProcessor::ShareEffectState(const CPostProcessor& other)
{
if (!HasSameEffectChain(other))
return false;
for (size_t i = 0; i < m_effects.size(); ++i)
m_effects[i]->ShareState(*other.m_effects[i]);
return true;
}
void CPostProcessor::Update(const D12FrameFormat& srcFormat)
{
for (const auto& effect : m_effects)
effect->Update(srcFormat);
}
bool CPostProcessor::NeedsReconfigure(const D12FrameFormat& srcFormat) const
{
if (!m_configured ||
srcFormat.desc.Width != m_srcFormat.desc.Width ||
srcFormat.desc.Height != m_srcFormat.desc.Height ||
srcFormat.desc.Format != m_srcFormat.desc.Format ||
srcFormat.format != m_srcFormat.format ||
srcFormat.width != m_srcFormat.width ||
srcFormat.height != m_srcFormat.height ||
srcFormat.hdr != m_srcFormat.hdr ||
srcFormat.hdrPQ != m_srcFormat.hdrPQ ||
srcFormat.colorTransform != m_srcFormat.colorTransform)
return true;
for (const auto& effect : m_effects)
if (effect->NeedsReconfigure())
return true;
return false;
}
bool CPostProcessor::RequiresFullDamage() const
{
for (const auto& effect : m_effects)
if (effect->RequiresFullDamage())
return true;
return false;
}
bool CPostProcessor::Configure(const D12FrameFormat& srcFormat,
bool * formatChanged)
{
if (formatChanged)
*formatChanged = false;
if (!NeedsReconfigure(srcFormat))
{
// Static HDR metadata may change independently of the resource format.
// Propagate it without recreating resources or post-processing state.
CopyHDRMetadata(m_srcFormat, srcFormat);
CopyHDRMetadata(m_dstFormat, srcFormat);
return true;
}
D12FrameFormat oldDst = m_dstFormat;
D12FrameFormat cur = srcFormat;
CPostProcessEffect * outputEffect = nullptr;
bool effectsActive = false;
for (const auto& effect : m_effects)
{
D12FrameFormat dst = cur;
switch (effect->SetFormat(m_device, cur, dst))
{
case PostProcessStatus::SUCCESS:
effect->Enabled = true;
effectsActive = true;
cur = dst;
outputEffect = effect.get();
DEBUG_INFO("Post-processing effect active: %s", effect->GetName());
break;
case PostProcessStatus::BYPASS_EFFECT:
effect->Enabled = false;
break;
case PostProcessStatus::FAILED:
DEBUG_ERROR("Failed to configure post-processing effect: %s", effect->GetName());
return false;
}
}
D3D12_PLACED_SUBRESOURCE_FOOTPRINT copyLayout = {};
CPostProcessEffect * copyEffect = nullptr;
unsigned pitch = 0;
unsigned dataHeight = 0;
if (outputEffect && outputEffect->GetCopyLayout(&pitch, &dataHeight))
copyEffect = outputEffect;
else
{
if (cur.desc.Dimension != D3D12_RESOURCE_DIMENSION_TEXTURE2D)
{
DEBUG_ERROR("Post-processing output has no copy implementation");
return false;
}
m_device->GetCopyableFootprints(
&cur.desc,
0,
1,
0,
&copyLayout,
nullptr,
nullptr,
nullptr);
pitch = copyLayout.Footprint.RowPitch;
dataHeight = cur.desc.Height;
}
if (!pitch || !dataHeight ||
pitch > (std::numeric_limits<size_t>::max)() / dataHeight)
{
DEBUG_ERROR("Invalid post-processing output layout");
return false;
}
const size_t frameSize = (size_t)pitch * dataHeight;
if (copyEffect && cur.desc.Width < frameSize)
{
DEBUG_ERROR("Post-processing output buffer is too small");
return false;
}
m_srcFormat = srcFormat;
m_dstFormat = cur;
m_copyLayout = copyLayout;
m_copyEffect = copyEffect;
m_frameSize = frameSize;
m_pitch = pitch;
m_effectsActive = effectsActive;
m_configured = true;
if (formatChanged)
*formatChanged =
oldDst.desc.Width != m_dstFormat.desc.Width ||
oldDst.desc.Height != m_dstFormat.desc.Height ||
oldDst.desc.Format != m_dstFormat.desc.Format ||
oldDst.dataWidth != m_dstFormat.dataWidth ||
oldDst.dataHeight != m_dstFormat.dataHeight ||
oldDst.pitch != m_dstFormat.pitch ||
oldDst.format != m_dstFormat.format ||
oldDst.width != m_dstFormat.width ||
oldDst.height != m_dstFormat.height ||
oldDst.hdr != m_dstFormat.hdr ||
oldDst.hdrPQ != m_dstFormat.hdrPQ ||
oldDst.sdrWhiteLevel != m_dstFormat.sdrWhiteLevel ||
oldDst.colorTransform != m_dstFormat.colorTransform;
return true;
}
void CPostProcessor::GetTimingToken(
unsigned * effectIndex, uint64_t * token) const
{
if (effectIndex)
*effectIndex = 0;
if (token)
*token = 0;
for (size_t i = 0; i < m_effects.size(); ++i)
{
const uint64_t value = m_effects[i]->GetTimingToken();
if (!value)
continue;
if (effectIndex)
*effectIndex = (unsigned)i;
if (token)
*token = value;
return;
}
}
void CPostProcessor::RecordTiming(
unsigned effectIndex, uint64_t token, bool fullCopy, uint64_t totalTime)
{
if (!token || effectIndex >= m_effects.size())
return;
m_effects[effectIndex]->RecordTiming(token, fullCopy, totalTime);
}
bool CPostProcessor::ShouldCopyFully(
const RECT dirtyRects[], unsigned nbDirtyRects) const
{
return m_copyEffect &&
m_copyEffect->ShouldCopyFully(dirtyRects, nbDirtyRects);
}
void CPostProcessor::CopyToFrameBuffer(
const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src,
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
{
if (m_copyEffect)
{
m_copyEffect->CopyFrame(
commandList, dst, src, dirtyRects, nbDirtyRects, fullCopy);
return;
}
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
srcLoc.pResource = src;
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
srcLoc.SubresourceIndex = 0;
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
dstLoc.pResource = dst;
if (dst->GetDesc().Dimension == D3D12_RESOURCE_DIMENSION_TEXTURE2D)
{
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
dstLoc.SubresourceIndex = 0;
}
else
{
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
dstLoc.PlacedFootprint = m_copyLayout;
}
if (fullCopy)
{
commandList->CopyTextureRegion(
&dstLoc, 0, 0, 0, &srcLoc, nullptr);
return;
}
for (const RECT * rect = dirtyRects;
rect < dirtyRects + nbDirtyRects; ++rect)
{
D3D12_BOX box = {};
box.left = rect->left;
box.top = rect->top;
box.front = 0;
box.right = rect->right;
box.bottom = rect->bottom;
box.back = 1;
commandList->CopyTextureRegion(
&dstLoc, box.left, box.top, 0, &srcLoc, &box);
}
}
void CPostProcessor::CopyToCandidate(
const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src) const
{
CopyToFrameBuffer(
commandList, dst, src, nullptr, 0, true);
}
void CPostProcessor::CopyFromCandidate(
const ComPtr<ID3D12GraphicsCommandList>& commandList,
ID3D12Resource * dst, ID3D12Resource * src,
const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const
{
if (m_copyEffect)
{
m_copyEffect->CopyFrame(
commandList, dst, src, dirtyRects, nbDirtyRects, fullCopy);
return;
}
D3D12_TEXTURE_COPY_LOCATION srcLoc = {};
srcLoc.pResource = src;
srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
srcLoc.PlacedFootprint = m_copyLayout;
D3D12_TEXTURE_COPY_LOCATION dstLoc = {};
dstLoc.pResource = dst;
dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
dstLoc.PlacedFootprint = m_copyLayout;
if (fullCopy)
{
commandList->CopyBufferRegion(
dst, 0, src, 0, m_frameSize);
return;
}
for (const RECT * rect = dirtyRects;
rect < dirtyRects + nbDirtyRects; ++rect)
{
D3D12_BOX box = {};
box.left = rect->left;
box.top = rect->top;
box.front = 0;
box.right = rect->right;
box.bottom = rect->bottom;
box.back = 1;
commandList->CopyTextureRegion(
&dstLoc, box.left, box.top, 0, &srcLoc, &box);
}
}
void CPostProcessor::AdjustFrameDamage(RECT dirtyRects[], unsigned * nbDirtyRects)
{
for (const auto& effect : m_effects)
if (effect->Enabled)
effect->AdjustDamage(dirtyRects, nbDirtyRects);
}
ComPtr<ID3D12Resource> CPostProcessor::Run(
const ComPtr<ID3D12GraphicsCommandList>& commandList,
const ComPtr<ID3D12Resource>& src, RECT dirtyRects[],
unsigned * nbDirtyRects)
{
ComPtr<ID3D12Resource> next = src;
for (const auto& effect : m_effects)
{
if (!effect->Enabled)
continue;
//DEBUG_TRACE("Run post-processing effect: %s", effect->GetName());
effect->AdjustDamage(dirtyRects, nbDirtyRects);
next = effect->Run(m_device, commandList, next, dirtyRects, nbDirtyRects);
}
return next;
}