/** * 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 #include #include #include #include #include struct CD3D12Device; extern "C" { #include "common/types.h" } using namespace Microsoft::WRL; enum class PostProcessStatus { SUCCESS, BYPASS_EFFECT, FAILED }; struct D12ColorTransform { bool matrixEnabled = false; float matrix[3][4] = {}; float scalar = 1.0f; bool lutEnabled = false; float lut[4096][4] = {}; }; bool IsIdentityColorTransform(const D12ColorTransform& transform); struct D12FrameFormat { D3D12_RESOURCE_DESC desc = {}; unsigned dataWidth = 0; unsigned dataHeight = 0; unsigned pitch = 0; unsigned width = 0; unsigned height = 0; FrameType format = FRAME_TYPE_INVALID; bool hdr = false; bool hdrPQ = false; bool hdrMetadata = false; uint32_t sdrWhiteLevel = LG_SDR_WHITE_LEVEL_DEFAULT; std::shared_ptr colorTransform; // HDR static metadata (SMPTE ST 2086) // Display color primaries in 0.00002 units (xy coordinates) uint16_t displayPrimary[3][2]; // White point in 0.00002 units uint16_t whitePoint[2]; // Max mastering display luminance in whole cd/m² uint32_t maxDisplayLuminance; // Min mastering display luminance in 0.0001 cd/m² units uint32_t minDisplayLuminance; // MaxCLL and MaxFALL in cd/m² uint32_t maxContentLightLevel; uint32_t maxFrameAverageLightLevel; }; class CPostProcessEffect { public: virtual ~CPostProcessEffect() {} virtual const char * GetName() const = 0; virtual void ShareState(const CPostProcessEffect& other) { UNREFERENCED_PARAMETER(other); } virtual void Update(const D12FrameFormat& format) { UNREFERENCED_PARAMETER(format); } virtual bool NeedsReconfigure() const { return false; } virtual bool RequiresFullDamage() const { return false; } virtual uint64_t GetTimingToken() const { return 0; } virtual void RecordTiming( uint64_t token, bool fullCopy, uint64_t totalTime) { UNREFERENCED_PARAMETER(token); UNREFERENCED_PARAMETER(fullCopy); UNREFERENCED_PARAMETER(totalTime); } // A final effect with a non-texture output owns its framebuffer copy. virtual bool GetCopyLayout( unsigned * pitch, unsigned * dataHeight) const { UNREFERENCED_PARAMETER(pitch); UNREFERENCED_PARAMETER(dataHeight); return false; } virtual bool ShouldCopyFully( const RECT dirtyRects[], unsigned nbDirtyRects) const { UNREFERENCED_PARAMETER(dirtyRects); UNREFERENCED_PARAMETER(nbDirtyRects); return false; } virtual void CopyFrame( const ComPtr& commandList, ID3D12Resource * dst, ID3D12Resource * src, const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const { UNREFERENCED_PARAMETER(commandList); UNREFERENCED_PARAMETER(dst); UNREFERENCED_PARAMETER(src); UNREFERENCED_PARAMETER(dirtyRects); UNREFERENCED_PARAMETER(nbDirtyRects); UNREFERENCED_PARAMETER(fullCopy); } virtual PostProcessStatus SetFormat(const ComPtr& device, const D12FrameFormat& src, D12FrameFormat& dst) = 0; virtual void AdjustDamage(RECT dirtyRects[], unsigned * nbDirtyRects) { UNREFERENCED_PARAMETER(dirtyRects); UNREFERENCED_PARAMETER(nbDirtyRects); } virtual ComPtr Run(const ComPtr& device, const ComPtr& commandList, const ComPtr& src, RECT dirtyRects[], unsigned * nbDirtyRects) = 0; bool Enabled = false; }; class CPostProcessor { private: std::shared_ptr m_dx12Device; ComPtr m_device; std::vector> m_effects; D12FrameFormat m_srcFormat = {}; D12FrameFormat m_dstFormat = {}; D3D12_PLACED_SUBRESOURCE_FOOTPRINT m_copyLayout = {}; CPostProcessEffect * m_copyEffect = nullptr; size_t m_frameSize = 0; unsigned m_pitch = 0; bool m_effectsActive = false; bool m_configured = false; public: bool Init(std::shared_ptr dx12Device, bool enableEffects); void Reset(); bool HasSameEffectChain(const CPostProcessor& other) const; bool ShareEffectState(const CPostProcessor& other); void Update(const D12FrameFormat& srcFormat); bool NeedsReconfigure(const D12FrameFormat& srcFormat) const; bool RequiresFullDamage() const; bool Configure(const D12FrameFormat& srcFormat, bool * formatChanged); void AdjustFrameDamage(RECT dirtyRects[], unsigned * nbDirtyRects); ComPtr Run( const ComPtr& commandList, const ComPtr& src, RECT dirtyRects[], unsigned * nbDirtyRects); const D12FrameFormat& GetOutputFormat() const { return m_dstFormat; } bool HasActiveEffects() const { return m_effectsActive; } void GetTimingToken(unsigned * effectIndex, uint64_t * token) const; void RecordTiming(unsigned effectIndex, uint64_t token, bool fullCopy, uint64_t totalTime); unsigned GetOutputPitch() const { return m_pitch; } size_t GetOutputSize () const { return m_frameSize; } bool ShouldCopyFully( const RECT dirtyRects[], unsigned nbDirtyRects) const; void CopyFrame( const ComPtr& commandList, ID3D12Resource * dst, ID3D12Resource * src, const RECT dirtyRects[], unsigned nbDirtyRects, bool fullCopy) const; };