1
0
mirror of https://github.com/ncblakely/GiantsTools synced 2024-07-03 20:11:45 +02:00
GiantsTools/Sdk/External/DirectXTK/Src/DualPostProcess.cpp
2021-01-23 15:40:09 -08:00

347 lines
9.9 KiB
C++

//--------------------------------------------------------------------------------------
// File: DualPostProcess.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// http://go.microsoft.com/fwlink/?LinkId=248929
//--------------------------------------------------------------------------------------
#include "pch.h"
#include "PostProcess.h"
#include "AlignedNew.h"
#include "CommonStates.h"
#include "BufferHelpers.h"
#include "DemandCreate.h"
#include "DirectXHelpers.h"
#include "SharedResourcePool.h"
using namespace DirectX;
using Microsoft::WRL::ComPtr;
namespace
{
constexpr int c_MaxSamples = 16;
constexpr int Dirty_ConstantBuffer = 0x01;
constexpr int Dirty_Parameters = 0x02;
// Constant buffer layout. Must match the shader!
__declspec(align(16)) struct PostProcessConstants
{
XMVECTOR sampleOffsets[c_MaxSamples];
XMVECTOR sampleWeights[c_MaxSamples];
};
static_assert((sizeof(PostProcessConstants) % 16) == 0, "CB size not padded correctly");
}
// Include the precompiled shader code.
namespace
{
#if defined(_XBOX_ONE) && defined(_TITLE)
#include "Shaders/Compiled/XboxOnePostProcess_VSQuad.inc"
#include "Shaders/Compiled/XboxOnePostProcess_PSMerge.inc"
#include "Shaders/Compiled/XboxOnePostProcess_PSBloomCombine.inc"
#else
#include "Shaders/Compiled/PostProcess_VSQuad.inc"
#include "Shaders/Compiled/PostProcess_PSMerge.inc"
#include "Shaders/Compiled/PostProcess_PSBloomCombine.inc"
#endif
}
namespace
{
struct ShaderBytecode
{
void const* code;
size_t length;
};
const ShaderBytecode pixelShaders[] =
{
{ PostProcess_PSMerge, sizeof(PostProcess_PSMerge) },
{ PostProcess_PSBloomCombine, sizeof(PostProcess_PSBloomCombine) },
};
static_assert(_countof(pixelShaders) == DualPostProcess::Effect_Max, "array/max mismatch");
// Factory for lazily instantiating shaders.
class DeviceResources
{
public:
DeviceResources(_In_ ID3D11Device* device)
: stateObjects(device),
mDevice(device),
mVertexShader{},
mPixelShaders{},
mMutex{}
{ }
// Gets or lazily creates the vertex shader.
ID3D11VertexShader* GetVertexShader()
{
return DemandCreate(mVertexShader, mMutex, [&](ID3D11VertexShader** pResult) -> HRESULT
{
HRESULT hr = mDevice->CreateVertexShader(PostProcess_VSQuad, sizeof(PostProcess_VSQuad), nullptr, pResult);
if (SUCCEEDED(hr))
SetDebugObjectName(*pResult, "DualPostProcess");
return hr;
});
}
// Gets or lazily creates the specified pixel shader.
ID3D11PixelShader* GetPixelShader(unsigned int shaderIndex)
{
assert(shaderIndex < DualPostProcess::Effect_Max);
_Analysis_assume_(shaderIndex < DualPostProcess::Effect_Max);
return DemandCreate(mPixelShaders[shaderIndex], mMutex, [&](ID3D11PixelShader** pResult) -> HRESULT
{
HRESULT hr = mDevice->CreatePixelShader(pixelShaders[shaderIndex].code, pixelShaders[shaderIndex].length, nullptr, pResult);
if (SUCCEEDED(hr))
SetDebugObjectName(*pResult, "DualPostProcess");
return hr;
});
}
CommonStates stateObjects;
protected:
ComPtr<ID3D11Device> mDevice;
ComPtr<ID3D11VertexShader> mVertexShader;
ComPtr<ID3D11PixelShader> mPixelShaders[DualPostProcess::Effect_Max];
std::mutex mMutex;
};
}
class DualPostProcess::Impl : public AlignedNew<PostProcessConstants>
{
public:
Impl(_In_ ID3D11Device* device);
void Process(_In_ ID3D11DeviceContext* deviceContext, std::function<void __cdecl()>& setCustomState);
void SetDirtyFlag() noexcept { mDirtyFlags = INT_MAX; }
// Fields.
PostProcessConstants constants;
DualPostProcess::Effect fx;
ComPtr<ID3D11ShaderResourceView> texture;
ComPtr<ID3D11ShaderResourceView> texture2;
float mergeWeight1;
float mergeWeight2;
float bloomIntensity;
float bloomBaseIntensity;
float bloomSaturation;
float bloomBaseSaturation;
private:
int mDirtyFlags;
ConstantBuffer<PostProcessConstants> mConstantBuffer;
// Per-device resources.
std::shared_ptr<DeviceResources> mDeviceResources;
static SharedResourcePool<ID3D11Device*, DeviceResources> deviceResourcesPool;
};
// Global pool of per-device DualPostProcess resources.
SharedResourcePool<ID3D11Device*, DeviceResources> DualPostProcess::Impl::deviceResourcesPool;
// Constructor.
DualPostProcess::Impl::Impl(_In_ ID3D11Device* device)
: constants{},
fx(DualPostProcess::Merge),
mergeWeight1(0.5f),
mergeWeight2(0.5f),
bloomIntensity(1.25f),
bloomBaseIntensity(1.f),
bloomSaturation(1.f),
bloomBaseSaturation(1.f),
mDirtyFlags(INT_MAX),
mConstantBuffer(device),
mDeviceResources(deviceResourcesPool.DemandCreate(device))
{
if (device->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0)
{
throw std::exception("DualPostProcess requires Feature Level 10.0 or later");
}
SetDebugObjectName(mConstantBuffer.GetBuffer(), "DualPostProcess");
}
// Sets our state onto the D3D device.
void DualPostProcess::Impl::Process(
_In_ ID3D11DeviceContext* deviceContext,
std::function<void __cdecl()>& setCustomState)
{
// Set the texture.
ID3D11ShaderResourceView* textures[2] = { texture.Get(), texture2.Get() };
deviceContext->PSSetShaderResources(0, 2, textures);
auto sampler = mDeviceResources->stateObjects.LinearClamp();
deviceContext->PSSetSamplers(0, 1, &sampler);
// Set state objects.
deviceContext->OMSetBlendState(mDeviceResources->stateObjects.Opaque(), nullptr, 0xffffffff);
deviceContext->OMSetDepthStencilState(mDeviceResources->stateObjects.DepthNone(), 0);
deviceContext->RSSetState(mDeviceResources->stateObjects.CullNone());
// Set shaders.
auto vertexShader = mDeviceResources->GetVertexShader();
auto pixelShader = mDeviceResources->GetPixelShader(fx);
deviceContext->VSSetShader(vertexShader, nullptr, 0);
deviceContext->PSSetShader(pixelShader, nullptr, 0);
// Set constants.
if (mDirtyFlags & Dirty_Parameters)
{
mDirtyFlags &= ~Dirty_Parameters;
mDirtyFlags |= Dirty_ConstantBuffer;
switch (fx)
{
case Merge:
constants.sampleWeights[0] = XMVectorReplicate(mergeWeight1);
constants.sampleWeights[1] = XMVectorReplicate(mergeWeight2);
break;
case BloomCombine:
constants.sampleWeights[0] = XMVectorSet(bloomBaseSaturation, bloomSaturation, 0.f, 0.f);
constants.sampleWeights[1] = XMVectorReplicate(bloomBaseIntensity);
constants.sampleWeights[2] = XMVectorReplicate(bloomIntensity);
break;
default:
break;
}
}
#if defined(_XBOX_ONE) && defined(_TITLE)
void *grfxMemory;
mConstantBuffer.SetData(deviceContext, constants, &grfxMemory);
Microsoft::WRL::ComPtr<ID3D11DeviceContextX> deviceContextX;
ThrowIfFailed(deviceContext->QueryInterface(IID_GRAPHICS_PPV_ARGS(deviceContextX.GetAddressOf())));
auto buffer = mConstantBuffer.GetBuffer();
deviceContextX->PSSetPlacementConstantBuffer(0, buffer, grfxMemory);
#else
if (mDirtyFlags & Dirty_ConstantBuffer)
{
mDirtyFlags &= ~Dirty_ConstantBuffer;
mConstantBuffer.SetData(deviceContext, constants);
}
// Set the constant buffer.
auto buffer = mConstantBuffer.GetBuffer();
deviceContext->PSSetConstantBuffers(0, 1, &buffer);
#endif
if (setCustomState)
{
setCustomState();
}
// Draw quad.
deviceContext->IASetInputLayout(nullptr);
deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
deviceContext->Draw(3, 0);
}
// Public constructor.
DualPostProcess::DualPostProcess(_In_ ID3D11Device* device)
: pImpl(std::make_unique<Impl>(device))
{
}
// Move constructor.
DualPostProcess::DualPostProcess(DualPostProcess&& moveFrom) noexcept
: pImpl(std::move(moveFrom.pImpl))
{
}
// Move assignment.
DualPostProcess& DualPostProcess::operator= (DualPostProcess&& moveFrom) noexcept
{
pImpl = std::move(moveFrom.pImpl);
return *this;
}
// Public destructor.
DualPostProcess::~DualPostProcess()
{
}
// IPostProcess methods.
void DualPostProcess::Process(
_In_ ID3D11DeviceContext* deviceContext,
_In_opt_ std::function<void __cdecl()> setCustomState)
{
pImpl->Process(deviceContext, setCustomState);
}
// Shader control.
void DualPostProcess::SetEffect(Effect fx)
{
if (fx >= Effect_Max)
throw std::out_of_range("Effect not defined");
pImpl->fx = fx;
pImpl->SetDirtyFlag();
}
// Properties
void DualPostProcess::SetSourceTexture(_In_opt_ ID3D11ShaderResourceView* value)
{
pImpl->texture = value;
}
void DualPostProcess::SetSourceTexture2(_In_opt_ ID3D11ShaderResourceView* value)
{
pImpl->texture2 = value;
}
void DualPostProcess::SetMergeParameters(float weight1, float weight2)
{
pImpl->mergeWeight1 = weight1;
pImpl->mergeWeight2 = weight2;
pImpl->SetDirtyFlag();
}
void DualPostProcess::SetBloomCombineParameters(float bloom, float base, float bloomSaturation, float baseSaturation)
{
pImpl->bloomIntensity = bloom;
pImpl->bloomBaseIntensity = base;
pImpl->bloomSaturation = bloomSaturation;
pImpl->bloomBaseSaturation = baseSaturation;
pImpl->SetDirtyFlag();
}