feat: 着色器效果渲染 (p3)

This commit is contained in:
Xu 2026-04-05 20:31:04 +08:00
commit f6463be543
6 changed files with 340 additions and 149 deletions

View file

@ -16,12 +16,29 @@ void ComputeContext::SetRoot32BitConstants(
_commandList->SetComputeRoot32BitConstants(rootParameterIndex, constantCount, pData, 0);
}
void ComputeContext::SetComputeRootConstantBufferView(
uint32_t rootParameterIndex,
D3D12_GPU_VIRTUAL_ADDRESS bufferLocation
) noexcept {
// 存在 DATA_STATIC 标志时 SetComputeRootConstantBufferView 会检查资源状态
if (_d3d12Context->GetRootSignatureVersion() >= D3D_ROOT_SIGNATURE_VERSION_1_1) {
_FlushBarriers();
}
_commandList->SetComputeRootConstantBufferView(rootParameterIndex, bufferLocation);
}
void ComputeContext::SetRootDescriptorTable(
uint32_t rootParameterIndex,
uint32_t baseDescriptorOffset
) noexcept {
assert(baseDescriptorOffset != std::numeric_limits<uint32_t>::max());
// 存在 DATA_STATIC 标志时 SetComputeRootDescriptorTable 会检查资源状态
if (_d3d12Context->GetRootSignatureVersion() >= D3D_ROOT_SIGNATURE_VERSION_1_1) {
_FlushBarriers();
}
_commandList->SetComputeRootDescriptorTable(
rootParameterIndex,
_d3d12Context->GetDescriptorHeap().GetGpuHandle(baseDescriptorOffset)
@ -59,7 +76,7 @@ void GraphicsContext::SetRootDescriptorTable(
) noexcept {
assert(baseDescriptorOffset != std::numeric_limits<uint32_t>::max());
// 存在 DATA_STATIC_WHILE_SET_AT_EXECUTE 时 SetGraphicsRootDescriptorTable 会检查资源状态
// 存在 DATA_STATIC 标志时 SetGraphicsRootDescriptorTable 会检查资源状态
if (_d3d12Context->GetRootSignatureVersion() >= D3D_ROOT_SIGNATURE_VERSION_1_1) {
_FlushBarriers();
}

View file

@ -153,6 +153,11 @@ public:
const void* pData
) noexcept;
void SetComputeRootConstantBufferView(
uint32_t rootParameterIndex,
D3D12_GPU_VIRTUAL_ADDRESS bufferLocation
) noexcept;
void SetRootDescriptorTable(
uint32_t rootParameterIndex,
uint32_t baseDescriptorOffset
@ -160,7 +165,7 @@ public:
void Dispatch(
uint32_t threadGroupCountX,
uint32_t threadGroupCountY,
uint32_t threadGroupCountY = 1,
uint32_t threadGroupCountZ = 1
) noexcept;

View file

@ -167,8 +167,9 @@ bool EffectsDrawer::Initialize(
texDesc.Width = effectData.outputSize.width;
texDesc.Height = effectData.outputSize.height;
hr = device->CreateCommittedResource(&heapProps, heapFlags, &texDesc,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS, nullptr, IID_PPV_ARGS(&effectData.outputTexture));
hr = device->CreateCommittedResource(
&heapProps, heapFlags, &texDesc, D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
nullptr, IID_PPV_ARGS(&effectData.outputTexture));
if (FAILED(hr)) {
Logger::Get().ComError("CreateCommittedResource 失败", hr);
return false;
@ -254,18 +255,128 @@ HRESULT EffectsDrawer::Draw(
//commandList->EndQuery(_queryHeap.get(), D3D12_QUERY_TYPE_TIMESTAMP, queryHeapIndex);
for (auto& effectData : _effectDatas) {
const uint32_t effectCount = (uint32_t)_effectDatas.size();
// 如果多个连续的效果都不能渲染,则合并为一个 CatmullRom
uint32_t catmullRomStartIdx = std::numeric_limits<uint32_t>::max();
for (uint32_t effectIdx = 0; effectIdx < effectCount; ++effectIdx) {
EffectDrawerState state;
std::string msg;
HRESULT hr = effectData.drawer->Update(state, msg);
HRESULT hr = _effectDatas[effectIdx].drawer->Update(state, msg);
if (FAILED(hr)) {
Logger::Get().ComError("ShaderEffectDrawer::Update 失败", hr);
return hr;
}
if (state != EffectDrawerState::Ready) {
if (catmullRomStartIdx == std::numeric_limits<uint32_t>::max()) {
catmullRomStartIdx = effectIdx;
}
continue;
}
if (catmullRomStartIdx != std::numeric_limits<uint32_t>::max()) {
catmullRomStartIdx = std::numeric_limits<uint32_t>::max();
SizeU inputSize;
uint32_t inputSrv;
if (catmullRomStartIdx == 0) {
inputSize = _inputSize;
inputSrv = inputSrvOffset;
} else {
uint32_t prevIdx = catmullRomStartIdx - 1;
inputSize = _effectDatas[prevIdx].outputSize;
inputSrv = _descriptorBaseOffset + prevIdx * 2;
computeContext.InsertTransitionBarrier(
_effectDatas[prevIdx].outputTexture.get(),
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
}
computeContext.InsertTransitionBarrier(
_effectDatas[size_t(effectIdx - 1)].outputTexture.get(),
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
_catmullRomDrawer.Draw(
computeContext,
inputSize,
_effectDatas[size_t(effectIdx - 1)].outputSize,
inputSrv,
_descriptorBaseOffset + effectIdx * 2 - 1,
false
);
}
bool writeToRingBuffer = effectIdx == effectCount - 1 &&
_effectDatas[effectIdx].outputSize == _outputSize;
if (effectIdx != 0) {
computeContext.InsertTransitionBarrier(
_effectDatas[size_t(effectIdx - 1)].outputTexture.get(),
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
}
if (!writeToRingBuffer) {
computeContext.InsertTransitionBarrier(
_effectDatas[effectIdx].outputTexture.get(),
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
}
hr = _effectDatas[effectIdx].drawer->Draw(
computeContext,
effectIdx == 0 ? inputSrvOffset : _descriptorBaseOffset + (effectIdx - 1) * 2,
writeToRingBuffer ? outputUavOffset : _descriptorBaseOffset + effectIdx * 2 + 1
);
if (FAILED(hr)) {
Logger::Get().ComError("EffectDrawerBase::Draw 失败", hr);
return hr;
}
}
_catmullRomDrawer.Draw(
computeContext, _inputSize, _outputSize, inputSrvOffset, outputUavOffset, false);
if (catmullRomStartIdx != std::numeric_limits<uint32_t>::max()) {
SizeU inputSize;
uint32_t inputSrv;
if (catmullRomStartIdx == 0) {
inputSize = _inputSize;
inputSrv = inputSrvOffset;
} else {
uint32_t prevIdx = catmullRomStartIdx - 1;
inputSize = _effectDatas[prevIdx].outputSize;
inputSrv = _descriptorBaseOffset + prevIdx * 2;
computeContext.InsertTransitionBarrier(
_effectDatas[prevIdx].outputTexture.get(),
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
}
_catmullRomDrawer.Draw(
computeContext, inputSize, _outputSize, inputSrv, outputUavOffset, false);
} else if (_effectDatas.back().outputSize != _outputSize) {
computeContext.InsertTransitionBarrier(
_effectDatas.back().outputTexture.get(),
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
_catmullRomDrawer.Draw(
computeContext,
_effectDatas.back().outputSize,
_outputSize,
_descriptorBaseOffset + (effectCount - 1) * 2,
outputUavOffset,
false
);
}
// commandList->EndQuery(_queryHeap.get(), D3D12_QUERY_TYPE_TIMESTAMP, queryHeapIndex + 1);
// commandList->ResolveQueryData(_queryHeap.get(), D3D12_QUERY_TYPE_TIMESTAMP, queryHeapIndex, 2,

View file

@ -20,7 +20,7 @@ ShaderEffectDrawer::~ShaderEffectDrawer() noexcept {
#ifdef _DEBUG
if (_descriptorBaseOffset != std::numeric_limits<uint32_t>::max()) {
_d3d12Context->GetDescriptorHeap().Free(
_descriptorBaseOffset, (uint32_t)_textureDescriptorMap.size() + 1);
_descriptorBaseOffset, (uint32_t)_textureDescriptorMap.size());
}
#endif
@ -122,8 +122,8 @@ HRESULT ShaderEffectDrawer::Update(EffectDrawerState& state, std::string& messag
HRESULT ShaderEffectDrawer::Draw(
ComputeContext& computeContext,
uint32_t /*inputSrvOffset*/,
uint32_t /*outputUavOffset*/
uint32_t inputSrvOffset,
uint32_t outputUavOffset
) noexcept {
assert(_drawInfo);
@ -140,7 +140,67 @@ HRESULT ShaderEffectDrawer::Draw(
);
}
return E_NOTIMPL;
for (uint32_t i = 0; i < _passDatas.size(); ++i) {
const _PassData& curPassData = _passDatas[i];
const ShaderEffectPassDesc& passDesc = _drawInfo->passes[i];
computeContext.SetPipelineState(curPassData.pso.get());
computeContext.SetRootSignature(curPassData.rootSignature.get());
// 合并状态转换
for (uint32_t input : passDesc.inputs) {
if (input == 0) {
continue;
}
auto oldState = std::exchange(_textureStates[size_t(input - 2)],
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
if (oldState != D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE) {
computeContext.InsertTransitionBarrier(
_textures[size_t(input - 2)].get(),
oldState,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
);
}
}
for (uint32_t output : passDesc.outputs) {
if (output == 1) {
continue;
}
auto oldState = std::exchange(_textureStates[size_t(output - 2)],
D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
if (oldState != D3D12_RESOURCE_STATE_UNORDERED_ACCESS) {
computeContext.InsertTransitionBarrier(
_textures[size_t(output - 2)].get(),
oldState,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS
);
}
}
computeContext.SetComputeRootConstantBufferView(0, _constantBuffer->GetGPUVirtualAddress());
uint32_t rootParameterIndex = 1;
if (!passDesc.inputs.empty() && passDesc.inputs[0] == 0) {
computeContext.SetRootDescriptorTable(rootParameterIndex++, inputSrvOffset);
}
if (passDesc.outputs[0] == 1) {
computeContext.SetRootDescriptorTable(rootParameterIndex++, outputUavOffset);
}
// 不需要额外的描述符时 passData.descriptorBaseOffset 为 UINT_MAX
if (curPassData.descriptorBaseOffset != std::numeric_limits<uint32_t>::max()) {
computeContext.SetRootDescriptorTable(rootParameterIndex++, curPassData.descriptorBaseOffset);
}
computeContext.Dispatch(curPassData.dispatchCount.first, curPassData.dispatchCount.second);
}
return S_OK;
}
HRESULT ShaderEffectDrawer::_CreateDeviceResources() {
@ -323,6 +383,7 @@ HRESULT ShaderEffectDrawer::_CreateDeviceResources() {
}
}
// 不需要额外的描述符时 passData.descriptorBaseOffset 为 UINT_MAX
if (!descriptorCounts.empty()) {
// 按需要的描述符数量从多到少排序,这可以提高复用描述符的概率
std::sort(
@ -382,173 +443,19 @@ HRESULT ShaderEffectDrawer::_CreateDeviceResources() {
}
HRESULT hr = _d3d12Context->GetDescriptorHeap()
.Alloc((uint32_t)_textureDescriptorMap.size() + 1, _descriptorBaseOffset);
.Alloc((uint32_t)_textureDescriptorMap.size(), _descriptorBaseOffset);
if (FAILED(hr)) {
Logger::Get().ComError("DescriptorHeap::Alloc 失败", hr);
return hr;
}
// 索引 0 是 CBV
for (_PassData& passData : _passDatas) {
passData.descriptorBaseOffset += _descriptorBaseOffset + 1;
if (passData.descriptorBaseOffset != std::numeric_limits<uint32_t>::max()) {
passData.descriptorBaseOffset += _descriptorBaseOffset;
}
}
}
// 常量缓冲区可以复用。常量缓冲区布局如下:
// uint2 __inputSize;
// uint2 __outputSize;
// float2 __inputPt;
// float2 __outputPt;
// float2 __scale;
// ↓ PS 样式参数 ↓
// [float2 __pass1OutputPt;]
// [float2 __pass2OutputPt;]
// [...]
// ↓ WCG/HDR 参数 ↓
// [float __maxLuminance;]
// [float __sdrWhiteLevel;]
// ↓ 效果参数 ↓
// [float param1;]
// [uint param2;]
// [...]
if (!_constantBuffer) {
// 10 个内置常量
uint32_t paramCount = 10;
// PS 样式需要额外常量,除了最后一个通道
for (uint32_t i = 0, end = (uint32_t)_drawInfo->passes.size() - 1; i < end; ++i) {
if (bool(_drawInfo->passes[i].flags & ShaderEffectPassFlags::PSStyle)) {
paramCount += 2;
}
}
// WCG/HDR 需要额外常量,始终预留位置使常量缓冲区可以复用
paramCount += 2;
// 未启用内联参数时每个参数占用一个常量
if (!options.IsInlineParams()) {
paramCount += (uint32_t)_effectInfo->params.size();
}
D3D12_HEAP_FLAGS heapFlag = _d3d12Context->IsHeapFlagCreateNotZeroedSupported() ?
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(UINT64(paramCount * 4));
HRESULT hr = device->CreateCommittedResource(
&heapProperties,
heapFlag,
&bufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&_constantUploadBuffer)
);
if (FAILED(hr)) {
Logger::Get().ComError("CreateCommittedResource 失败", hr);
return hr;
}
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
// 常量缓冲区必须对齐到 256 字节
bufferDesc.Width = (bufferDesc.Width + 255) & ~255;
hr = device->CreateCommittedResource(
&heapProperties,
heapFlag,
&bufferDesc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS(&_constantBuffer)
);
if (FAILED(hr)) {
Logger::Get().ComError("CreateCommittedResource 失败", hr);
return hr;
}
auto& descriptorHeap = _d3d12Context->GetDescriptorHeap();
D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {
.BufferLocation = _constantBuffer->GetGPUVirtualAddress(),
.SizeInBytes = (UINT)bufferDesc.Width
};
device->CreateConstantBufferView(
&cbvDesc, descriptorHeap.GetCpuHandle(_descriptorBaseOffset));
// 无需解除映射
D3D12_RANGE readRange{};
hr = _constantUploadBuffer->Map(0, &readRange, &_constantUploadBufferData);
if (FAILED(hr)) {
Logger::Get().ComError("ID3D12Resource::Map 失败", hr);
return hr;
}
}
// 更新 _constantUploadBuffer_constantBuffer 将在 Draw 中更新
{
using Constant32 = DirectXHelper::Constant32;
// SmallVector 中数据地址偏移量是 16 字节alignas(16) 使 SmallVector
// 和其中数据都对齐到 16 字节边界。
alignas(16) SmallVector<Constant32, 32> constants;
assert((uint8_t*)constants.data() - (uint8_t*)&constants == 16);
constants.emplace_back(Constant32::UInt(_inputSize.width));
constants.emplace_back(Constant32::UInt(_inputSize.height));
constants.emplace_back(Constant32::UInt(_outputSize.width));
constants.emplace_back(Constant32::UInt(_outputSize.height));
constants.emplace_back(Constant32::Float(1.0f / _inputSize.width));
constants.emplace_back(Constant32::Float(1.0f / _inputSize.height));
constants.emplace_back(Constant32::Float(1.0f / _outputSize.width));
constants.emplace_back(Constant32::Float(1.0f / _outputSize.height));
constants.emplace_back(Constant32::Float((float)_outputSize.width / _inputSize.width));
constants.emplace_back(Constant32::Float((float)_outputSize.height / _inputSize.height));
// PS 样式参数
for (uint32_t i = 0, end = (uint32_t)_drawInfo->passes.size() - 1; i < end; ++i) {
if (bool(_drawInfo->passes[i].flags & ShaderEffectPassFlags::PSStyle)) {
uint32_t output = _drawInfo->passes[i].outputs[0];
if (output == 1) {
constants.emplace_back(Constant32::Float(1.0f / _outputSize.width));
constants.emplace_back(Constant32::Float(1.0f / _outputSize.height));
} else {
D3D12_RESOURCE_DESC texDesc = _textures[size_t(output - 2)]->GetDesc();
constants.emplace_back(Constant32::Float(1.0f / texDesc.Width));
constants.emplace_back(Constant32::Float(1.0f / texDesc.Height));
}
}
}
// WCG/HDR 参数
if (bool(_effectInfo->flags & EffectFlags::SupportAdvancedColor) &&
_colorInfo.kind != winrt::AdvancedColorKind::StandardDynamicRange)
{
constants.emplace_back(Constant32::Float(_colorInfo.maxLuminance));
constants.emplace_back(Constant32::Float(_colorInfo.sdrWhiteLevel));
}
// 效果参数
if (!options.IsInlineParams()) {
for (const EffectParameterDesc& paramDesc : _effectInfo->params) {
auto it = _effectOption->parameters.find(paramDesc.name);
float value = it == _effectOption->parameters.end() ? paramDesc.defaultValue : it->second;
switch (paramDesc.type) {
case EffectParameterType::Float:
constants.emplace_back(Constant32::Float(value));
break;
case EffectParameterType::Int:
constants.emplace_back(Constant32::Int(std::lround(value)));
break;
default:
assert(paramDesc.type == EffectParameterType::UInt);
constants.emplace_back(Constant32::UInt((uint32_t)std::lround(value)));
break;
}
}
}
_constantsDataSize = (uint32_t)constants.size() * 4;
assert(_constantsDataSize <= _constantUploadBuffer->GetDesc().Width);
std::memcpy(_constantUploadBufferData, constants.data(), _constantsDataSize);
_isConstantBufferOutdated = true;
}
{
_textures.resize(_drawInfo->textures.size());
@ -632,9 +539,8 @@ HRESULT ShaderEffectDrawer::_CreateDeviceResources() {
auto& descriptorHeap = _d3d12Context->GetDescriptorHeap();
const uint32_t descriptorSize = descriptorHeap.GetDescriptorSize();
// 索引 0 是 CBV
CD3DX12_CPU_DESCRIPTOR_HANDLE baseHandle(
descriptorHeap.GetCpuHandle(_descriptorBaseOffset), descriptorSize);
descriptorHeap.GetCpuHandle(_descriptorBaseOffset));
CD3DX12_SHADER_RESOURCE_VIEW_DESC srvDesc =
CD3DX12_SHADER_RESOURCE_VIEW_DESC::Tex2D(dxgiFormat, 1);
@ -649,7 +555,7 @@ HRESULT ShaderEffectDrawer::_CreateDeviceResources() {
device->CreateShaderResourceView(_textures[texIdx].get(), &srvDesc,
CD3DX12_CPU_DESCRIPTOR_HANDLE(baseHandle, (INT)offset, descriptorSize));
}
// 为了和 SRV 做区分UAV 的索引加上纹理总数
uint32_t uavIdx = uint32_t(texIdx + _textures.size());
CD3DX12_UNORDERED_ACCESS_VIEW_DESC uavDesc =
@ -667,8 +573,160 @@ HRESULT ShaderEffectDrawer::_CreateDeviceResources() {
}
}
}
if (_textureStates.empty()) {
// 纹理创建时处于 UNORDERED_ACCESS 状态
_textureStates.resize(_textures.size(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS);
}
}
// 常量缓冲区可以复用。常量缓冲区布局如下:
// uint2 __inputSize;
// uint2 __outputSize;
// float2 __inputPt;
// float2 __outputPt;
// float2 __scale;
// ↓ PS 样式参数 ↓
// [float2 __pass1OutputPt;]
// [float2 __pass2OutputPt;]
// [...]
// ↓ WCG/HDR 参数 ↓
// [float __maxLuminance;]
// [float __sdrWhiteLevel;]
// ↓ 效果参数 ↓
// [float param1;]
// [uint param2;]
// [...]
if (!_constantBuffer) {
// 10 个内置常量
uint32_t paramCount = 10;
// PS 样式需要额外常量,除了最后一个通道
for (uint32_t i = 0, end = (uint32_t)_drawInfo->passes.size() - 1; i < end; ++i) {
if (bool(_drawInfo->passes[i].flags & ShaderEffectPassFlags::PSStyle)) {
paramCount += 2;
}
}
// WCG/HDR 需要额外常量,始终预留位置使常量缓冲区可以复用
paramCount += 2;
// 未启用内联参数时每个参数占用一个常量
if (!options.IsInlineParams()) {
paramCount += (uint32_t)_effectInfo->params.size();
}
D3D12_HEAP_FLAGS heapFlag = _d3d12Context->IsHeapFlagCreateNotZeroedSupported() ?
D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
CD3DX12_HEAP_PROPERTIES heapProperties(D3D12_HEAP_TYPE_UPLOAD);
CD3DX12_RESOURCE_DESC bufferDesc = CD3DX12_RESOURCE_DESC::Buffer(UINT64(paramCount * 4));
HRESULT hr = device->CreateCommittedResource(
&heapProperties,
heapFlag,
&bufferDesc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&_constantUploadBuffer)
);
if (FAILED(hr)) {
Logger::Get().ComError("CreateCommittedResource 失败", hr);
return hr;
}
heapProperties.Type = D3D12_HEAP_TYPE_DEFAULT;
// 常量缓冲区必须对齐到 256 字节
bufferDesc.Width = (bufferDesc.Width + 255) & ~255;
hr = device->CreateCommittedResource(
&heapProperties,
heapFlag,
&bufferDesc,
D3D12_RESOURCE_STATE_COMMON,
nullptr,
IID_PPV_ARGS(&_constantBuffer)
);
if (FAILED(hr)) {
Logger::Get().ComError("CreateCommittedResource 失败", hr);
return hr;
}
// 无需解除映射
D3D12_RANGE readRange{};
hr = _constantUploadBuffer->Map(0, &readRange, &_constantUploadBufferData);
if (FAILED(hr)) {
Logger::Get().ComError("ID3D12Resource::Map 失败", hr);
return hr;
}
}
// 更新 _constantUploadBuffer_constantBuffer 将在 Draw 中更新
{
using Constant32 = DirectXHelper::Constant32;
// SmallVector 中数据地址偏移量是 16 字节alignas(16) 使 SmallVector
// 和其中数据都对齐到 16 字节边界。
alignas(16) SmallVector<Constant32, 32> constants;
assert((uint8_t*)constants.data() - (uint8_t*)&constants == 16);
constants.emplace_back(Constant32::UInt(_inputSize.width));
constants.emplace_back(Constant32::UInt(_inputSize.height));
constants.emplace_back(Constant32::UInt(_outputSize.width));
constants.emplace_back(Constant32::UInt(_outputSize.height));
constants.emplace_back(Constant32::Float(1.0f / _inputSize.width));
constants.emplace_back(Constant32::Float(1.0f / _inputSize.height));
constants.emplace_back(Constant32::Float(1.0f / _outputSize.width));
constants.emplace_back(Constant32::Float(1.0f / _outputSize.height));
constants.emplace_back(Constant32::Float((float)_outputSize.width / _inputSize.width));
constants.emplace_back(Constant32::Float((float)_outputSize.height / _inputSize.height));
// PS 样式参数
for (uint32_t i = 0, end = (uint32_t)_drawInfo->passes.size() - 1; i < end; ++i) {
if (bool(_drawInfo->passes[i].flags & ShaderEffectPassFlags::PSStyle)) {
uint32_t output = _drawInfo->passes[i].outputs[0];
if (output == 1) {
constants.emplace_back(Constant32::Float(1.0f / _outputSize.width));
constants.emplace_back(Constant32::Float(1.0f / _outputSize.height));
} else {
D3D12_RESOURCE_DESC texDesc = _textures[size_t(output - 2)]->GetDesc();
constants.emplace_back(Constant32::Float(1.0f / texDesc.Width));
constants.emplace_back(Constant32::Float(1.0f / texDesc.Height));
}
}
}
// WCG/HDR 参数
if (bool(_effectInfo->flags & EffectFlags::SupportAdvancedColor) &&
_colorInfo.kind != winrt::AdvancedColorKind::StandardDynamicRange)
{
constants.emplace_back(Constant32::Float(_colorInfo.maxLuminance));
constants.emplace_back(Constant32::Float(_colorInfo.sdrWhiteLevel));
}
// 效果参数
if (!options.IsInlineParams()) {
for (const EffectParameterDesc& paramDesc : _effectInfo->params) {
auto it = _effectOption->parameters.find(paramDesc.name);
float value = it == _effectOption->parameters.end() ? paramDesc.defaultValue : it->second;
switch (paramDesc.type) {
case EffectParameterType::Float:
constants.emplace_back(Constant32::Float(value));
break;
case EffectParameterType::Int:
constants.emplace_back(Constant32::Int(std::lround(value)));
break;
default:
assert(paramDesc.type == EffectParameterType::UInt);
constants.emplace_back(Constant32::UInt((uint32_t)std::lround(value)));
break;
}
}
}
_constantsDataSize = (uint32_t)constants.size() * 4;
assert(_constantsDataSize <= _constantUploadBuffer->GetDesc().Width);
std::memcpy(_constantUploadBufferData, constants.data(), _constantsDataSize);
_isConstantBufferOutdated = true;
}
for (uint32_t passIdx = 0; passIdx < passCount; ++passIdx) {
const ShaderEffectPassDesc& curPassDesc = _drawInfo->passes[passIdx];

View file

@ -43,8 +43,8 @@ private:
winrt::com_ptr<ID3D12RootSignature> rootSignature;
winrt::com_ptr<ID3D12PipelineState> pso;
// 这里是 _descriptorBaseOffset 中成员的引用,无需释放
uint32_t descriptorBaseOffset;
SizeU dispatchCount;
uint32_t descriptorBaseOffset = std::numeric_limits<uint32_t>::max();
std::pair<uint32_t, uint32_t> dispatchCount;
};
SmallVector<_PassData> _passDatas;
@ -54,9 +54,9 @@ private:
uint32_t _constantsDataSize = 0;
SmallVector<winrt::com_ptr<ID3D12Resource>> _textures;
// 描述符布局: CBV | [SRV] | [UAV] | [SRV] | ...
// 多个通道的 SRV 和 UAV 可能合并_textureDescriptorMap 保存了布局。描述符总数是
// _textureDescriptorMap.size() + 1
SmallVector<D3D12_RESOURCE_STATES> _textureStates;
// 描述符布局: [SRV] | [UAV] | [SRV] | ...
// 多个通道的 SRV 和 UAV 可能合并_textureDescriptorMap 保存了布局
uint32_t _descriptorBaseOffset = std::numeric_limits<uint32_t>::max();
// 和 ShaderEffectPassDesc 的 inputs/outputs 不同,这里存储 _textures 中元素索引,
// 从 0 开始。虽然可以用额外字段区分 SRV 和 UAV但这里想尽可能避免堆分配因此 UAV

View file

@ -99,7 +99,7 @@
<GenerateWindowsMetadata>false</GenerateWindowsMetadata>
<SubSystem>Windows</SubSystem>
<AdditionalDependencies>Gdi32.lib;Dwmapi.lib;Shell32.lib;Ole32.lib;Imagehlp.lib;Comctl32.lib;Shlwapi.lib;Magnification.lib;bcp47mrm.lib;Shcore.lib;Uxtheme.lib;Taskschd.lib;Dcomp.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<DelayLoadDLLs>d3dcompiler_47.dll;Magnification.dll;Imagehlp.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
<DelayLoadDLLs>d3dcompiler_47.dll;dxcompiler.dll;Magnification.dll;Imagehlp.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
</Link>
</ItemDefinitionGroup>
<!-- 删除 clang-cl 不支持的选项 -->