[dxvk] Don't cache shader modules for graphics pipelines

We're only ever going to need those when actually compiling a new
pipeline, so on average we're just wasting large amounts of memory
by keeping them around.

Trades several hundred MB of memory for a small increase in compile
times. Creating shader modules is typically very cheap.
This commit is contained in:
Philip Rebohle 2019-04-03 20:01:36 +02:00
parent 79e867624a
commit 2bd09e52e7
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 57 additions and 56 deletions

View File

@ -44,36 +44,23 @@ namespace dxvk {
const Rc<DxvkShader>& tes,
const Rc<DxvkShader>& gs,
const Rc<DxvkShader>& fs)
: m_vkd(pipeMgr->m_device->vkd()), m_pipeMgr(pipeMgr) {
DxvkDescriptorSlotMapping slotMapping;
if (vs != nullptr) vs ->defineResourceSlots(slotMapping);
if (tcs != nullptr) tcs->defineResourceSlots(slotMapping);
if (tes != nullptr) tes->defineResourceSlots(slotMapping);
if (gs != nullptr) gs ->defineResourceSlots(slotMapping);
if (fs != nullptr) fs ->defineResourceSlots(slotMapping);
: m_vkd(pipeMgr->m_device->vkd()), m_pipeMgr(pipeMgr),
m_vs(vs), m_tcs(tcs), m_tes(tes), m_gs(gs), m_fs(fs) {
if (vs != nullptr) vs ->defineResourceSlots(m_slotMapping);
if (tcs != nullptr) tcs->defineResourceSlots(m_slotMapping);
if (tes != nullptr) tes->defineResourceSlots(m_slotMapping);
if (gs != nullptr) gs ->defineResourceSlots(m_slotMapping);
if (fs != nullptr) fs ->defineResourceSlots(m_slotMapping);
slotMapping.makeDescriptorsDynamic(
m_slotMapping.makeDescriptorsDynamic(
pipeMgr->m_device->options().maxNumDynamicUniformBuffers,
pipeMgr->m_device->options().maxNumDynamicStorageBuffers);
m_layout = new DxvkPipelineLayout(m_vkd,
slotMapping.bindingCount(),
slotMapping.bindingInfos(),
m_slotMapping.bindingCount(),
m_slotMapping.bindingInfos(),
VK_PIPELINE_BIND_POINT_GRAPHICS);
DxvkShaderModuleCreateInfo moduleInfo;
moduleInfo.fsDualSrcBlend = false;
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;
@ -102,16 +89,11 @@ namespace dxvk {
Rc<DxvkShader> DxvkGraphicsPipeline::getShader(
VkShaderStageFlagBits stage) const {
switch (stage) {
case VK_SHADER_STAGE_VERTEX_BIT:
return m_vs != nullptr ? m_vs->shader() : nullptr;
case VK_SHADER_STAGE_GEOMETRY_BIT:
return m_gs != nullptr ? m_gs->shader() : nullptr;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
return m_tcs != nullptr ? m_tcs->shader() : nullptr;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
return m_tes != nullptr ? m_tes->shader() : nullptr;
case VK_SHADER_STAGE_FRAGMENT_BIT:
return m_fs != nullptr ? m_fs->shader() : nullptr;
case VK_SHADER_STAGE_VERTEX_BIT: return m_vs;
case VK_SHADER_STAGE_GEOMETRY_BIT: return m_gs;
case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT: return m_tcs;
case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT: return m_tes;
case VK_SHADER_STAGE_FRAGMENT_BIT: return m_fs;
default:
return nullptr;
}
@ -218,19 +200,24 @@ namespace dxvk {
std::vector<VkPipelineShaderStageCreateInfo> stages;
bool useDualSrcBlend = state.omBlendAttachments[0].blendEnable && (
DxvkShaderModuleCreateInfo moduleInfo;
moduleInfo.fsDualSrcBlend = 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));
auto vsm = createShaderModule(m_vs, moduleInfo);
auto gsm = createShaderModule(m_gs, moduleInfo);
auto tcsm = createShaderModule(m_tcs, moduleInfo);
auto tesm = createShaderModule(m_tes, moduleInfo);
auto fsm = createShaderModule(m_fs, moduleInfo);
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 (fs != nullptr) stages.push_back(fs->stageInfo(&specInfo));
if (m_vs != nullptr) stages.push_back(vsm->stageInfo(&specInfo));
if (m_tcs != nullptr) stages.push_back(tcsm->stageInfo(&specInfo));
if (m_tes != nullptr) stages.push_back(tesm->stageInfo(&specInfo));
if (m_gs != nullptr) stages.push_back(gsm->stageInfo(&specInfo));
if (m_fs != nullptr) stages.push_back(fsm->stageInfo(&specInfo));
// Fix up color write masks using the component mappings
std::array<VkPipelineColorBlendAttachmentState, MaxNumRenderTargets> omBlendAttachments;
@ -264,7 +251,7 @@ namespace dxvk {
}
int32_t rasterizedStream = m_gs != nullptr
? m_gs->shader()->shaderOptions().rasterizedStream
? m_gs->shaderOptions().rasterizedStream
: 0;
VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo;
@ -441,6 +428,15 @@ namespace dxvk {
}
Rc<DxvkShaderModule> DxvkGraphicsPipeline::createShaderModule(
const Rc<DxvkShader>& shader,
const DxvkShaderModuleCreateInfo& info) const {
return shader != nullptr
? shader->createShaderModule(m_vkd, m_slotMapping, info)
: nullptr;
}
bool DxvkGraphicsPipeline::validatePipelineState(
const DxvkGraphicsPipelineStateInfo& state) const {
// Validate vertex input - each input slot consumed by the
@ -488,11 +484,11 @@ namespace dxvk {
void DxvkGraphicsPipeline::logPipelineState(
LogLevel level,
const DxvkGraphicsPipelineStateInfo& state) const {
if (m_vs != nullptr) Logger::log(level, str::format(" vs : ", m_vs ->shader()->debugName()));
if (m_tcs != nullptr) Logger::log(level, str::format(" tcs : ", m_tcs->shader()->debugName()));
if (m_tes != nullptr) Logger::log(level, str::format(" tes : ", m_tes->shader()->debugName()));
if (m_gs != nullptr) Logger::log(level, str::format(" gs : ", m_gs ->shader()->debugName()));
if (m_fs != nullptr) Logger::log(level, str::format(" fs : ", m_fs ->shader()->debugName()));
if (m_vs != nullptr) Logger::log(level, str::format(" vs : ", m_vs ->debugName()));
if (m_tcs != nullptr) Logger::log(level, str::format(" tcs : ", m_tcs->debugName()));
if (m_tes != nullptr) Logger::log(level, str::format(" tes : ", m_tes->debugName()));
if (m_gs != nullptr) Logger::log(level, str::format(" gs : ", m_gs ->debugName()));
if (m_fs != nullptr) Logger::log(level, str::format(" fs : ", m_fs ->debugName()));
for (uint32_t i = 0; i < state.ilAttributeCount; i++) {
const VkVertexInputAttributeDescription& attr = state.ilAttributes[i];

View File

@ -243,16 +243,17 @@ namespace dxvk {
VkPipeline pipeline;
};
Rc<vk::DeviceFn> m_vkd;
DxvkPipelineManager* m_pipeMgr;
Rc<vk::DeviceFn> m_vkd;
DxvkPipelineManager* m_pipeMgr;
Rc<DxvkPipelineLayout> m_layout;
Rc<DxvkShaderModule> m_vs;
Rc<DxvkShaderModule> m_tcs;
Rc<DxvkShaderModule> m_tes;
Rc<DxvkShaderModule> m_gs;
Rc<DxvkShaderModule> m_fs;
Rc<DxvkShaderModule> m_fs2;
DxvkDescriptorSlotMapping m_slotMapping;
Rc<DxvkShader> m_vs;
Rc<DxvkShader> m_tcs;
Rc<DxvkShader> m_tes;
Rc<DxvkShader> m_gs;
Rc<DxvkShader> m_fs;
Rc<DxvkPipelineLayout> m_layout;
uint32_t m_vsIn = 0;
uint32_t m_fsOut = 0;
@ -279,6 +280,10 @@ namespace dxvk {
void destroyPipeline(
VkPipeline pipeline) const;
Rc<DxvkShaderModule> createShaderModule(
const Rc<DxvkShader>& shader,
const DxvkShaderModuleCreateInfo& info) const;
bool validatePipelineState(
const DxvkGraphicsPipelineStateInfo& state) const;