1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-01-19 05:52:11 +01:00

[dxvk] Patch fragment shader for dual-source blending

This commit is contained in:
Philip Rebohle 2018-11-16 20:00:28 +01:00
parent f69c5e4c4e
commit e744117042
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
7 changed files with 75 additions and 15 deletions

View File

@ -36,7 +36,10 @@ namespace dxvk {
slotMapping.bindingInfos(),
VK_PIPELINE_BIND_POINT_COMPUTE);
m_cs = cs->createShaderModule(m_vkd, slotMapping);
DxvkShaderModuleCreateInfo moduleInfo;
moduleInfo.fsDualSrcBlend = false;
m_cs = cs->createShaderModule(m_vkd, slotMapping, moduleInfo);
}

View File

@ -61,11 +61,18 @@ namespace dxvk {
slotMapping.bindingInfos(),
VK_PIPELINE_BIND_POINT_GRAPHICS);
if (vs != nullptr) m_vs = vs ->createShaderModule(m_vkd, slotMapping);
if (tcs != nullptr) m_tcs = tcs->createShaderModule(m_vkd, slotMapping);
if (tes != nullptr) m_tes = tes->createShaderModule(m_vkd, slotMapping);
if (gs != nullptr) m_gs = gs ->createShaderModule(m_vkd, slotMapping);
if (fs != nullptr) m_fs = fs ->createShaderModule(m_vkd, slotMapping);
DxvkShaderModuleCreateInfo moduleInfo;
moduleInfo.fsDualSrcBlend = true;
DxvkShaderModuleCreateInfo moduleInfoDualSrc;
moduleInfoDualSrc.fsDualSrcBlend = true;
if (vs != nullptr) m_vs = vs ->createShaderModule(m_vkd, slotMapping, moduleInfo);
if (tcs != nullptr) m_tcs = tcs->createShaderModule(m_vkd, slotMapping, moduleInfo);
if (tes != nullptr) m_tes = tes->createShaderModule(m_vkd, slotMapping, moduleInfo);
if (gs != nullptr) m_gs = gs ->createShaderModule(m_vkd, slotMapping, moduleInfo);
if (fs != nullptr) m_fs = fs ->createShaderModule(m_vkd, slotMapping, moduleInfo);
if (fs != nullptr) m_fs2 = fs ->createShaderModule(m_vkd, slotMapping, moduleInfoDualSrc);
m_vsIn = vs != nullptr ? vs->interfaceSlots().inputSlots : 0;
m_fsOut = fs != nullptr ? fs->interfaceSlots().outputSlots : 0;
@ -200,12 +207,20 @@ namespace dxvk {
specInfo.pData = &specData;
std::vector<VkPipelineShaderStageCreateInfo> stages;
bool useDualSrcBlend = state.omBlendAttachments[0].blendEnable && (
util::isDualSourceBlendFactor(state.omBlendAttachments[0].srcColorBlendFactor) ||
util::isDualSourceBlendFactor(state.omBlendAttachments[0].dstColorBlendFactor) ||
util::isDualSourceBlendFactor(state.omBlendAttachments[0].srcAlphaBlendFactor) ||
util::isDualSourceBlendFactor(state.omBlendAttachments[0].dstAlphaBlendFactor));
Rc<DxvkShaderModule> fs = useDualSrcBlend ? m_fs2 : m_fs;
if (m_vs != nullptr) stages.push_back(m_vs->stageInfo(&specInfo));
if (m_tcs != nullptr) stages.push_back(m_tcs->stageInfo(&specInfo));
if (m_tes != nullptr) stages.push_back(m_tes->stageInfo(&specInfo));
if (m_gs != nullptr) stages.push_back(m_gs->stageInfo(&specInfo));
if (m_fs != nullptr) stages.push_back(m_fs->stageInfo(&specInfo));
if (fs != nullptr) stages.push_back(fs->stageInfo(&specInfo));
// Fix up color write masks using the component mappings
std::array<VkPipelineColorBlendAttachmentState, MaxNumRenderTargets> omBlendAttachments;

View File

@ -229,6 +229,7 @@ namespace dxvk {
Rc<DxvkShaderModule> m_tes;
Rc<DxvkShaderModule> m_gs;
Rc<DxvkShaderModule> m_fs;
Rc<DxvkShaderModule> m_fs2;
uint32_t m_vsIn = 0;
uint32_t m_fsOut = 0;

View File

@ -91,11 +91,22 @@ namespace dxvk {
// Gather the offsets where the binding IDs
// are stored so we can quickly remap them.
uint32_t o1VarId = 0;
for (auto ins : m_code) {
if (ins.opCode() == spv::OpDecorate
&& ((ins.arg(2) == spv::DecorationBinding)
|| (ins.arg(2) == spv::DecorationSpecId)))
m_idOffsets.push_back(ins.offset() + 3);
if (ins.opCode() == spv::OpDecorate) {
if (ins.arg(2) == spv::DecorationBinding
|| ins.arg(2) == spv::DecorationSpecId)
m_idOffsets.push_back(ins.offset() + 3);
if (ins.arg(2) == spv::DecorationLocation && ins.arg(3) == 1) {
m_o1LocOffset = ins.offset() + 3;
o1VarId = ins.arg(1);
}
if (ins.arg(2) == spv::DecorationIndex && ins.arg(1) == o1VarId)
m_o1IdxOffset = ins.offset() + 3;
}
}
}
@ -128,15 +139,21 @@ namespace dxvk {
Rc<DxvkShaderModule> DxvkShader::createShaderModule(
const Rc<vk::DeviceFn>& vkd,
const DxvkDescriptorSlotMapping& mapping) {
const DxvkDescriptorSlotMapping& mapping,
const DxvkShaderModuleCreateInfo& info) {
SpirvCodeBuffer spirvCode = m_code;
uint32_t* code = spirvCode.data();
// Remap resource binding IDs
uint32_t* code = spirvCode.data();
for (uint32_t ofs : m_idOffsets) {
if (code[ofs] < MaxNumResourceSlots)
code[ofs] = mapping.getBindingId(code[ofs]);
}
// For dual-source blending we need to re-map
// location 1, index 0 to location 0, index 1
if (info.fsDualSrcBlend && m_o1IdxOffset && m_o1LocOffset)
std::swap(code[m_o1IdxOffset], code[m_o1LocOffset]);
return new DxvkShaderModule(vkd, this, spirvCode);
}

View File

@ -101,6 +101,14 @@ namespace dxvk {
uint32_t* m_data = nullptr;
};
/**
* \brief Shader module create info
*/
struct DxvkShaderModuleCreateInfo {
bool fsDualSrcBlend;
};
/**
@ -162,11 +170,13 @@ namespace dxvk {
* Maps the binding slot numbers
* \param [in] vkd Vulkan device functions
* \param [in] mapping Resource slot mapping
* \param [in] info Module create info
* \returns The shader module
*/
Rc<DxvkShaderModule> createShaderModule(
const Rc<vk::DeviceFn>& vkd,
const DxvkDescriptorSlotMapping& mapping);
const DxvkDescriptorSlotMapping& mapping,
const DxvkShaderModuleCreateInfo& info);
/**
* \brief Inter-stage interface slots
@ -242,6 +252,9 @@ namespace dxvk {
DxvkShaderOptions m_options;
DxvkShaderConstData m_constData;
DxvkShaderKey m_key;
size_t m_o1IdxOffset = 0;
size_t m_o1LocOffset = 0;
};

View File

@ -149,4 +149,12 @@ namespace dxvk::util {
}
}
bool isDualSourceBlendFactor(VkBlendFactor factor) {
return factor == VK_BLEND_FACTOR_SRC1_COLOR
|| factor == VK_BLEND_FACTOR_SRC1_ALPHA
|| factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR
|| factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA;
}
}

View File

@ -212,4 +212,7 @@ namespace dxvk::util {
VkComponentSwizzle component,
uint32_t identity);
bool isDualSourceBlendFactor(
VkBlendFactor factor);
}