mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-08-09 08:41:31 +00:00
[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:
484
idd/LGIdd/postprocess/CPostProcessor.cpp
Normal file
484
idd/LGIdd/postprocess/CPostProcessor.cpp
Normal 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,
|
||||
©Layout,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
pitch = copyLayout.Footprint.RowPitch;
|
||||
dataHeight = cur.desc.Height;
|
||||
}
|
||||
|
||||
if (!pitch || !dataHeight ||
|
||||
pitch > (std::numeric_limits<size_t>::max)() / dataHeight)
|
||||
{
|
||||
DEBUG_ERROR("Invalid post-processing output layout");
|
||||
return false;
|
||||
}
|
||||
|
||||
const size_t frameSize = (size_t)pitch * dataHeight;
|
||||
if (copyEffect && cur.desc.Width < frameSize)
|
||||
{
|
||||
DEBUG_ERROR("Post-processing output buffer is too small");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_srcFormat = srcFormat;
|
||||
m_dstFormat = cur;
|
||||
m_copyLayout = copyLayout;
|
||||
m_copyEffect = copyEffect;
|
||||
m_frameSize = frameSize;
|
||||
m_pitch = pitch;
|
||||
m_effectsActive = effectsActive;
|
||||
m_configured = true;
|
||||
if (formatChanged)
|
||||
*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;
|
||||
}
|
||||
Reference in New Issue
Block a user