2018-03-29 12:06:53 +02:00
|
|
|
#include <chrono>
|
2017-12-07 21:47:38 +01:00
|
|
|
#include <cstring>
|
|
|
|
|
2018-01-16 15:00:19 +01:00
|
|
|
#include "dxvk_device.h"
|
2017-10-15 13:02:59 +02:00
|
|
|
#include "dxvk_graphics.h"
|
2018-05-26 14:54:29 +02:00
|
|
|
#include "dxvk_spec_const.h"
|
2017-10-15 13:02:59 +02:00
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
2017-12-07 21:47:38 +01:00
|
|
|
DxvkGraphicsPipelineStateInfo::DxvkGraphicsPipelineStateInfo() {
|
|
|
|
std::memset(this, 0, sizeof(DxvkGraphicsPipelineStateInfo));
|
2017-11-20 13:21:27 +01:00
|
|
|
}
|
|
|
|
|
2017-12-07 21:47:38 +01:00
|
|
|
|
|
|
|
DxvkGraphicsPipelineStateInfo::DxvkGraphicsPipelineStateInfo(
|
|
|
|
const DxvkGraphicsPipelineStateInfo& other) {
|
|
|
|
std::memcpy(this, &other, sizeof(DxvkGraphicsPipelineStateInfo));
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-12-07 21:47:38 +01:00
|
|
|
DxvkGraphicsPipelineStateInfo& DxvkGraphicsPipelineStateInfo::operator = (
|
|
|
|
const DxvkGraphicsPipelineStateInfo& other) {
|
|
|
|
std::memcpy(this, &other, sizeof(DxvkGraphicsPipelineStateInfo));
|
|
|
|
return *this;
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-10 21:28:20 +01:00
|
|
|
bool DxvkGraphicsPipelineStateInfo::operator == (const DxvkGraphicsPipelineStateInfo& other) const {
|
|
|
|
return std::memcmp(this, &other, sizeof(DxvkGraphicsPipelineStateInfo)) == 0;
|
2017-12-07 21:47:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-10 21:28:20 +01:00
|
|
|
bool DxvkGraphicsPipelineStateInfo::operator != (const DxvkGraphicsPipelineStateInfo& other) const {
|
|
|
|
return std::memcmp(this, &other, sizeof(DxvkGraphicsPipelineStateInfo)) != 0;
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
DxvkGraphicsPipelineInstance::DxvkGraphicsPipelineInstance(
|
|
|
|
const Rc<vk::DeviceFn>& vkd,
|
|
|
|
const DxvkGraphicsPipelineStateInfo& stateVector,
|
2018-05-10 14:15:47 +02:00
|
|
|
VkRenderPass renderPass,
|
|
|
|
VkPipeline basePipeline)
|
2018-05-09 22:23:50 +02:00
|
|
|
: m_vkd (vkd),
|
|
|
|
m_stateVector (stateVector),
|
2018-05-10 14:15:47 +02:00
|
|
|
m_renderPass (renderPass),
|
|
|
|
m_basePipeline(basePipeline),
|
|
|
|
m_fastPipeline(VK_NULL_HANDLE) {
|
2018-05-09 22:23:50 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkGraphicsPipelineInstance::~DxvkGraphicsPipelineInstance() {
|
2018-05-10 14:15:47 +02:00
|
|
|
m_vkd->vkDestroyPipeline(m_vkd->device(), m_basePipeline, nullptr);
|
|
|
|
m_vkd->vkDestroyPipeline(m_vkd->device(), m_fastPipeline, nullptr);
|
2018-05-09 22:23:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-15 13:02:59 +02:00
|
|
|
DxvkGraphicsPipeline::DxvkGraphicsPipeline(
|
2018-05-10 14:54:44 +02:00
|
|
|
const DxvkDevice* device,
|
|
|
|
const Rc<DxvkPipelineCache>& cache,
|
|
|
|
const Rc<DxvkPipelineCompiler>& compiler,
|
|
|
|
const Rc<DxvkShader>& vs,
|
|
|
|
const Rc<DxvkShader>& tcs,
|
|
|
|
const Rc<DxvkShader>& tes,
|
|
|
|
const Rc<DxvkShader>& gs,
|
|
|
|
const Rc<DxvkShader>& fs)
|
2018-01-16 15:00:19 +01:00
|
|
|
: m_device(device), m_vkd(device->vkd()),
|
2018-05-10 14:54:44 +02:00
|
|
|
m_cache(cache), m_compiler(compiler) {
|
2017-12-07 09:38:31 +01:00
|
|
|
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);
|
2017-11-20 14:11:09 +01:00
|
|
|
|
2018-06-22 00:33:47 +02:00
|
|
|
slotMapping.makeDescriptorsDynamic(
|
|
|
|
device->options().maxNumDynamicUniformBuffers,
|
|
|
|
device->options().maxNumDynamicStorageBuffers);
|
|
|
|
|
2018-01-23 17:40:36 +01:00
|
|
|
m_layout = new DxvkPipelineLayout(m_vkd,
|
2017-12-07 09:38:31 +01:00
|
|
|
slotMapping.bindingCount(),
|
2018-03-17 23:50:03 +01:00
|
|
|
slotMapping.bindingInfos(),
|
|
|
|
VK_PIPELINE_BIND_POINT_GRAPHICS);
|
2017-12-07 09:38:31 +01:00
|
|
|
|
2018-01-16 15:00:19 +01:00
|
|
|
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);
|
2018-01-12 14:25:26 +01:00
|
|
|
|
|
|
|
m_vsIn = vs != nullptr ? vs->interfaceSlots().inputSlots : 0;
|
|
|
|
m_fsOut = fs != nullptr ? fs->interfaceSlots().outputSlots : 0;
|
2018-04-08 21:49:30 +02:00
|
|
|
|
|
|
|
m_common.msSampleShadingEnable = fs != nullptr && fs->hasCapability(spv::CapabilitySampleRateShading);
|
|
|
|
m_common.msSampleShadingFactor = 1.0f;
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DxvkGraphicsPipeline::~DxvkGraphicsPipeline() {
|
2018-05-09 22:23:50 +02:00
|
|
|
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkPipeline DxvkGraphicsPipeline::getPipelineHandle(
|
2018-04-03 15:52:39 +02:00
|
|
|
const DxvkGraphicsPipelineStateInfo& state,
|
2018-05-03 19:33:41 +02:00
|
|
|
const DxvkRenderPass& renderPass,
|
2018-04-03 15:52:39 +02:00
|
|
|
DxvkStatCounters& stats) {
|
2018-05-03 19:33:41 +02:00
|
|
|
VkRenderPass renderPassHandle = renderPass.getDefaultHandle();
|
2017-10-15 13:02:59 +02:00
|
|
|
|
2018-05-01 16:45:28 +02:00
|
|
|
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
|
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
DxvkGraphicsPipelineInstance* pipeline =
|
|
|
|
this->findInstance(state, renderPassHandle);
|
|
|
|
|
|
|
|
if (pipeline != nullptr)
|
|
|
|
return pipeline->getPipeline();
|
2018-01-10 21:28:20 +01:00
|
|
|
}
|
2017-10-15 13:02:59 +02:00
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
// If the pipeline state vector is invalid, don't try
|
|
|
|
// to create a new pipeline, it won't work anyway.
|
|
|
|
if (!this->validatePipelineState(state))
|
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
|
|
|
|
// If no pipeline instance exists with the given state
|
|
|
|
// vector, create a new one and add it to the list.
|
2018-05-13 15:36:44 +02:00
|
|
|
VkPipeline newPipelineBase = m_basePipelineBase.load();
|
2018-05-10 14:54:44 +02:00
|
|
|
VkPipeline newPipelineHandle = this->compilePipeline(state, renderPassHandle,
|
2018-05-13 16:02:23 +02:00
|
|
|
m_compiler != nullptr ? VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT : 0,
|
|
|
|
newPipelineBase);
|
2018-05-09 22:23:50 +02:00
|
|
|
|
2018-05-10 14:15:47 +02:00
|
|
|
Rc<DxvkGraphicsPipelineInstance> newPipeline =
|
|
|
|
new DxvkGraphicsPipelineInstance(m_device->vkd(), state,
|
|
|
|
renderPassHandle, newPipelineHandle);
|
2018-01-12 14:25:26 +01:00
|
|
|
|
2018-05-01 16:45:28 +02:00
|
|
|
{ std::lock_guard<sync::Spinlock> lock(m_mutex);
|
|
|
|
|
|
|
|
// Discard the pipeline if another thread
|
|
|
|
// was faster compiling the same pipeline
|
2018-05-09 22:23:50 +02:00
|
|
|
DxvkGraphicsPipelineInstance* pipeline =
|
|
|
|
this->findInstance(state, renderPassHandle);
|
2018-05-01 16:45:28 +02:00
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
if (pipeline != nullptr)
|
|
|
|
return pipeline->getPipeline();
|
2018-05-01 16:45:28 +02:00
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
// Add new pipeline to the set
|
|
|
|
m_pipelines.push_back(newPipeline);
|
2018-05-01 16:45:28 +02:00
|
|
|
|
|
|
|
stats.addCtr(DxvkStatCounter::PipeCountGraphics, 1);
|
|
|
|
}
|
2018-05-10 14:54:44 +02:00
|
|
|
|
2018-05-13 15:36:44 +02:00
|
|
|
// Use the new pipeline as the base pipeline for derivative pipelines
|
|
|
|
if (newPipelineBase == VK_NULL_HANDLE && newPipelineHandle != VK_NULL_HANDLE)
|
|
|
|
m_basePipelineBase.compare_exchange_strong(newPipelineBase, newPipelineHandle);
|
|
|
|
|
2018-05-10 14:54:44 +02:00
|
|
|
// Compile optimized pipeline asynchronously
|
2018-05-13 16:02:23 +02:00
|
|
|
if (m_compiler != nullptr)
|
|
|
|
m_compiler->queueCompilation(this, newPipeline);
|
|
|
|
|
2018-05-10 14:54:44 +02:00
|
|
|
return newPipelineHandle;
|
2018-05-01 16:45:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-10 14:54:44 +02:00
|
|
|
void DxvkGraphicsPipeline::compileInstance(
|
2018-05-10 14:15:47 +02:00
|
|
|
const Rc<DxvkGraphicsPipelineInstance>& instance) {
|
|
|
|
// Compile an optimized version of the pipeline
|
2018-05-13 15:36:44 +02:00
|
|
|
VkPipeline newPipelineBase = m_fastPipelineBase.load();
|
2018-05-10 14:15:47 +02:00
|
|
|
VkPipeline newPipelineHandle = this->compilePipeline(
|
2018-05-10 14:54:44 +02:00
|
|
|
instance->m_stateVector, instance->m_renderPass,
|
2018-05-13 15:36:44 +02:00
|
|
|
0, m_fastPipelineBase);
|
|
|
|
|
2018-08-10 23:29:45 +02:00
|
|
|
if (!instance->setFastPipeline(newPipelineHandle)) {
|
|
|
|
// If another thread finished compiling an optimized version of this
|
|
|
|
// pipeline before this one finished, discard the new pipeline object.
|
2018-05-10 14:15:47 +02:00
|
|
|
m_vkd->vkDestroyPipeline(m_vkd->device(), newPipelineHandle, nullptr);
|
2018-08-10 23:29:45 +02:00
|
|
|
} else if (newPipelineBase == VK_NULL_HANDLE && newPipelineHandle != VK_NULL_HANDLE) {
|
|
|
|
// Use the new pipeline as the base pipeline for derivative pipelines.
|
|
|
|
m_fastPipelineBase.compare_exchange_strong(newPipelineBase, newPipelineHandle);
|
|
|
|
}
|
2018-05-10 14:15:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
DxvkGraphicsPipelineInstance* DxvkGraphicsPipeline::findInstance(
|
2018-05-01 16:45:28 +02:00
|
|
|
const DxvkGraphicsPipelineStateInfo& state,
|
2018-05-09 22:23:50 +02:00
|
|
|
VkRenderPass renderPass) const {
|
|
|
|
for (const auto& pipeline : m_pipelines) {
|
|
|
|
if (pipeline->isCompatible(state, renderPass))
|
|
|
|
return pipeline.ptr();
|
2018-05-01 16:45:28 +02:00
|
|
|
}
|
2018-04-03 15:52:39 +02:00
|
|
|
|
2018-05-09 22:23:50 +02:00
|
|
|
return nullptr;
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VkPipeline DxvkGraphicsPipeline::compilePipeline(
|
2018-01-10 22:54:00 +01:00
|
|
|
const DxvkGraphicsPipelineStateInfo& state,
|
2018-05-03 19:33:41 +02:00
|
|
|
VkRenderPass renderPass,
|
2018-05-10 14:54:44 +02:00
|
|
|
VkPipelineCreateFlags createFlags,
|
2018-01-10 22:54:00 +01:00
|
|
|
VkPipeline baseHandle) const {
|
2018-04-02 19:05:41 +02:00
|
|
|
if (Logger::logLevel() <= LogLevel::Debug) {
|
|
|
|
Logger::debug("Compiling graphics pipeline...");
|
|
|
|
this->logPipelineState(LogLevel::Debug, state);
|
|
|
|
}
|
2018-02-07 16:44:30 +01:00
|
|
|
|
2018-06-06 12:45:45 +02:00
|
|
|
std::array<VkDynamicState, 5> dynamicStates = {
|
2017-11-20 14:03:00 +01:00
|
|
|
VK_DYNAMIC_STATE_VIEWPORT,
|
|
|
|
VK_DYNAMIC_STATE_SCISSOR,
|
2018-06-06 12:45:45 +02:00
|
|
|
VK_DYNAMIC_STATE_DEPTH_BIAS,
|
2017-11-20 14:03:00 +01:00
|
|
|
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
|
|
|
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
|
|
|
};
|
2017-10-15 13:02:59 +02:00
|
|
|
|
2018-05-26 14:54:29 +02:00
|
|
|
DxvkSpecConstantData specData;
|
|
|
|
specData.rasterizerSampleCount = uint32_t(state.msSampleCount);
|
2018-01-10 11:44:40 +01:00
|
|
|
|
2018-05-26 14:54:29 +02:00
|
|
|
for (uint32_t i = 0; i < MaxNumActiveBindings; i++)
|
|
|
|
specData.activeBindings[i] = state.bsBindingState.isBound(i) ? VK_TRUE : VK_FALSE;
|
2018-01-10 11:44:40 +01:00
|
|
|
|
|
|
|
VkSpecializationInfo specInfo;
|
2018-05-26 14:54:29 +02:00
|
|
|
specInfo.mapEntryCount = g_specConstantMap.mapEntryCount();
|
|
|
|
specInfo.pMapEntries = g_specConstantMap.mapEntryData();
|
|
|
|
specInfo.dataSize = sizeof(specData);
|
|
|
|
specInfo.pData = &specData;
|
2018-01-10 11:44:40 +01:00
|
|
|
|
2017-11-20 14:03:00 +01:00
|
|
|
std::vector<VkPipelineShaderStageCreateInfo> stages;
|
|
|
|
|
2018-01-10 11:44:40 +01:00
|
|
|
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));
|
2018-09-01 16:49:24 +02:00
|
|
|
|
|
|
|
// Fix up color write masks using the component mappings
|
|
|
|
std::array<VkPipelineColorBlendAttachmentState, MaxNumRenderTargets> omBlendAttachments;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
|
|
|
|
omBlendAttachments[i] = state.omBlendAttachments[i];
|
|
|
|
omBlendAttachments[i].colorWriteMask = util::remapComponentMask(
|
|
|
|
state.omBlendAttachments[i].colorWriteMask,
|
|
|
|
state.omComponentMapping[i]);
|
2018-09-01 17:53:45 +02:00
|
|
|
|
|
|
|
specData.outputMappings[4 * i + 0] = util::getComponentIndex(state.omComponentMapping[i].r, 0);
|
|
|
|
specData.outputMappings[4 * i + 1] = util::getComponentIndex(state.omComponentMapping[i].g, 1);
|
|
|
|
specData.outputMappings[4 * i + 2] = util::getComponentIndex(state.omComponentMapping[i].b, 2);
|
|
|
|
specData.outputMappings[4 * i + 3] = util::getComponentIndex(state.omComponentMapping[i].a, 3);
|
2018-09-01 16:49:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate per-instance attribute divisors
|
2018-04-17 17:24:16 +02:00
|
|
|
std::array<VkVertexInputBindingDivisorDescriptionEXT, MaxNumVertexBindings> viDivisorDesc;
|
|
|
|
uint32_t viDivisorCount = 0;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < state.ilBindingCount; i++) {
|
|
|
|
if (state.ilBindings[i].inputRate == VK_VERTEX_INPUT_RATE_INSTANCE) {
|
|
|
|
const uint32_t id = viDivisorCount++;
|
|
|
|
|
|
|
|
viDivisorDesc[id].binding = state.ilBindings[i].binding;
|
|
|
|
viDivisorDesc[id].divisor = state.ilDivisors[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo;
|
|
|
|
viDivisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT;
|
|
|
|
viDivisorInfo.pNext = nullptr;
|
|
|
|
viDivisorInfo.vertexBindingDivisorCount = viDivisorCount;
|
|
|
|
viDivisorInfo.pVertexBindingDivisors = viDivisorDesc.data();
|
|
|
|
|
2017-12-07 21:47:38 +01:00
|
|
|
VkPipelineVertexInputStateCreateInfo viInfo;
|
|
|
|
viInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
2018-04-17 17:24:16 +02:00
|
|
|
viInfo.pNext = &viDivisorInfo;
|
2017-12-07 21:47:38 +01:00
|
|
|
viInfo.flags = 0;
|
|
|
|
viInfo.vertexBindingDescriptionCount = state.ilBindingCount;
|
|
|
|
viInfo.pVertexBindingDescriptions = state.ilBindings;
|
|
|
|
viInfo.vertexAttributeDescriptionCount = state.ilAttributeCount;
|
|
|
|
viInfo.pVertexAttributeDescriptions = state.ilAttributes;
|
|
|
|
|
2018-04-17 17:24:16 +02:00
|
|
|
if (viDivisorCount == 0)
|
|
|
|
viInfo.pNext = viDivisorInfo.pNext;
|
|
|
|
|
2018-07-19 23:10:12 +02:00
|
|
|
// TODO remove this once the extension is widely supported
|
2018-07-23 20:07:21 +02:00
|
|
|
if (!m_device->extensions().extVertexAttributeDivisor)
|
2018-07-19 23:10:12 +02:00
|
|
|
viInfo.pNext = viDivisorInfo.pNext;
|
|
|
|
|
2017-12-07 21:47:38 +01:00
|
|
|
VkPipelineInputAssemblyStateCreateInfo iaInfo;
|
|
|
|
iaInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
|
|
iaInfo.pNext = nullptr;
|
|
|
|
iaInfo.flags = 0;
|
|
|
|
iaInfo.topology = state.iaPrimitiveTopology;
|
|
|
|
iaInfo.primitiveRestartEnable = state.iaPrimitiveRestart;
|
|
|
|
|
2018-01-29 11:31:00 +01:00
|
|
|
VkPipelineTessellationStateCreateInfo tsInfo;
|
|
|
|
tsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
|
|
|
|
tsInfo.pNext = nullptr;
|
|
|
|
tsInfo.flags = 0;
|
|
|
|
tsInfo.patchControlPoints = state.iaPatchVertexCount;
|
|
|
|
|
2017-11-20 14:03:00 +01:00
|
|
|
VkPipelineViewportStateCreateInfo vpInfo;
|
2017-12-07 21:47:38 +01:00
|
|
|
vpInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
|
|
vpInfo.pNext = nullptr;
|
|
|
|
vpInfo.flags = 0;
|
|
|
|
vpInfo.viewportCount = state.rsViewportCount;
|
|
|
|
vpInfo.pViewports = nullptr;
|
|
|
|
vpInfo.scissorCount = state.rsViewportCount;
|
|
|
|
vpInfo.pScissors = nullptr;
|
|
|
|
|
|
|
|
VkPipelineRasterizationStateCreateInfo rsInfo;
|
|
|
|
rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
2018-04-04 15:09:24 +02:00
|
|
|
rsInfo.pNext = nullptr;
|
2017-12-07 21:47:38 +01:00
|
|
|
rsInfo.flags = 0;
|
2018-06-25 16:56:52 +02:00
|
|
|
rsInfo.depthClampEnable = state.rsDepthClampEnable;
|
|
|
|
rsInfo.rasterizerDiscardEnable= VK_FALSE;
|
2017-12-07 21:47:38 +01:00
|
|
|
rsInfo.polygonMode = state.rsPolygonMode;
|
|
|
|
rsInfo.cullMode = state.rsCullMode;
|
|
|
|
rsInfo.frontFace = state.rsFrontFace;
|
|
|
|
rsInfo.depthBiasEnable = state.rsDepthBiasEnable;
|
2018-06-06 12:45:45 +02:00
|
|
|
rsInfo.depthBiasConstantFactor= 0.0f;
|
|
|
|
rsInfo.depthBiasClamp = 0.0f;
|
|
|
|
rsInfo.depthBiasSlopeFactor = 0.0f;
|
2017-12-07 21:47:38 +01:00
|
|
|
rsInfo.lineWidth = 1.0f;
|
|
|
|
|
|
|
|
VkPipelineMultisampleStateCreateInfo msInfo;
|
|
|
|
msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
|
|
msInfo.pNext = nullptr;
|
|
|
|
msInfo.flags = 0;
|
|
|
|
msInfo.rasterizationSamples = state.msSampleCount;
|
2018-04-08 21:49:30 +02:00
|
|
|
msInfo.sampleShadingEnable = m_common.msSampleShadingEnable;
|
|
|
|
msInfo.minSampleShading = m_common.msSampleShadingFactor;
|
2017-12-07 21:47:38 +01:00
|
|
|
msInfo.pSampleMask = &state.msSampleMask;
|
|
|
|
msInfo.alphaToCoverageEnable = state.msEnableAlphaToCoverage;
|
|
|
|
msInfo.alphaToOneEnable = state.msEnableAlphaToOne;
|
|
|
|
|
|
|
|
VkPipelineDepthStencilStateCreateInfo dsInfo;
|
|
|
|
dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
|
|
dsInfo.pNext = nullptr;
|
|
|
|
dsInfo.flags = 0;
|
|
|
|
dsInfo.depthTestEnable = state.dsEnableDepthTest;
|
|
|
|
dsInfo.depthWriteEnable = state.dsEnableDepthWrite;
|
|
|
|
dsInfo.depthCompareOp = state.dsDepthCompareOp;
|
2018-06-06 13:11:09 +02:00
|
|
|
dsInfo.depthBoundsTestEnable = VK_FALSE;
|
2017-12-07 21:47:38 +01:00
|
|
|
dsInfo.stencilTestEnable = state.dsEnableStencilTest;
|
|
|
|
dsInfo.front = state.dsStencilOpFront;
|
|
|
|
dsInfo.back = state.dsStencilOpBack;
|
2018-06-06 13:11:09 +02:00
|
|
|
dsInfo.minDepthBounds = 0.0f;
|
|
|
|
dsInfo.maxDepthBounds = 1.0f;
|
2017-12-07 21:47:38 +01:00
|
|
|
|
|
|
|
VkPipelineColorBlendStateCreateInfo cbInfo;
|
|
|
|
cbInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
|
|
cbInfo.pNext = nullptr;
|
|
|
|
cbInfo.flags = 0;
|
|
|
|
cbInfo.logicOpEnable = state.omEnableLogicOp;
|
|
|
|
cbInfo.logicOp = state.omLogicOp;
|
|
|
|
cbInfo.attachmentCount = DxvkLimits::MaxNumRenderTargets;
|
2018-09-01 16:49:24 +02:00
|
|
|
cbInfo.pAttachments = omBlendAttachments.data();
|
2017-12-07 21:47:38 +01:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < 4; i++)
|
|
|
|
cbInfo.blendConstants[i] = 0.0f;
|
|
|
|
|
|
|
|
VkPipelineDynamicStateCreateInfo dyInfo;
|
|
|
|
dyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
|
|
dyInfo.pNext = nullptr;
|
|
|
|
dyInfo.flags = 0;
|
|
|
|
dyInfo.dynamicStateCount = dynamicStates.size();
|
|
|
|
dyInfo.pDynamicStates = dynamicStates.data();
|
2017-11-20 14:03:00 +01:00
|
|
|
|
|
|
|
VkGraphicsPipelineCreateInfo info;
|
2017-12-07 21:47:38 +01:00
|
|
|
info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
|
|
info.pNext = nullptr;
|
2018-05-10 14:54:44 +02:00
|
|
|
info.flags = createFlags;
|
2017-12-07 21:47:38 +01:00
|
|
|
info.stageCount = stages.size();
|
|
|
|
info.pStages = stages.data();
|
|
|
|
info.pVertexInputState = &viInfo;
|
|
|
|
info.pInputAssemblyState = &iaInfo;
|
2018-01-29 11:31:00 +01:00
|
|
|
info.pTessellationState = &tsInfo;
|
2017-12-07 21:47:38 +01:00
|
|
|
info.pViewportState = &vpInfo;
|
|
|
|
info.pRasterizationState = &rsInfo;
|
|
|
|
info.pMultisampleState = &msInfo;
|
|
|
|
info.pDepthStencilState = &dsInfo;
|
|
|
|
info.pColorBlendState = &cbInfo;
|
|
|
|
info.pDynamicState = &dyInfo;
|
|
|
|
info.layout = m_layout->pipelineLayout();
|
2018-05-03 19:33:41 +02:00
|
|
|
info.renderPass = renderPass;
|
2017-12-07 21:47:38 +01:00
|
|
|
info.subpass = 0;
|
2018-01-10 22:54:00 +01:00
|
|
|
info.basePipelineHandle = baseHandle;
|
|
|
|
info.basePipelineIndex = -1;
|
2017-11-20 14:03:00 +01:00
|
|
|
|
2018-05-10 14:54:44 +02:00
|
|
|
info.flags |= baseHandle == VK_NULL_HANDLE
|
|
|
|
? VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
|
|
|
|
: VK_PIPELINE_CREATE_DERIVATIVE_BIT;
|
|
|
|
|
2018-01-29 11:31:00 +01:00
|
|
|
if (tsInfo.patchControlPoints == 0)
|
|
|
|
info.pTessellationState = nullptr;
|
|
|
|
|
2018-03-29 12:06:53 +02:00
|
|
|
// Time pipeline compilation for debugging purposes
|
|
|
|
auto t0 = std::chrono::high_resolution_clock::now();
|
|
|
|
|
2017-11-20 14:03:00 +01:00
|
|
|
VkPipeline pipeline = VK_NULL_HANDLE;
|
|
|
|
if (m_vkd->vkCreateGraphicsPipelines(m_vkd->device(),
|
2018-01-31 00:48:39 +01:00
|
|
|
m_cache->handle(), 1, &info, nullptr, &pipeline) != VK_SUCCESS) {
|
|
|
|
Logger::err("DxvkGraphicsPipeline: Failed to compile pipeline");
|
2018-04-02 19:05:41 +02:00
|
|
|
this->logPipelineState(LogLevel::Error, state);
|
2018-01-31 00:48:39 +01:00
|
|
|
return VK_NULL_HANDLE;
|
|
|
|
}
|
|
|
|
|
2018-03-29 12:06:53 +02:00
|
|
|
auto t1 = std::chrono::high_resolution_clock::now();
|
|
|
|
auto td = std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0);
|
|
|
|
Logger::debug(str::format("DxvkGraphicsPipeline: Finished in ", td.count(), " ms"));
|
2017-11-20 14:03:00 +01:00
|
|
|
return pipeline;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-12 14:25:26 +01:00
|
|
|
bool DxvkGraphicsPipeline::validatePipelineState(
|
|
|
|
const DxvkGraphicsPipelineStateInfo& state) const {
|
|
|
|
// Validate vertex input - each input slot consumed by the
|
|
|
|
// vertex shader must be provided by the input layout.
|
|
|
|
uint32_t providedVertexInputs = 0;
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < state.ilAttributeCount; i++)
|
|
|
|
providedVertexInputs |= 1u << state.ilAttributes[i].location;
|
|
|
|
|
2018-05-10 21:59:57 +02:00
|
|
|
if ((providedVertexInputs & m_vsIn) != m_vsIn)
|
2018-01-12 14:25:26 +01:00
|
|
|
return false;
|
|
|
|
|
2018-03-21 15:22:18 +01:00
|
|
|
// If there are no tessellation shaders, we
|
|
|
|
// obviously cannot use tessellation patches.
|
2018-05-10 21:59:57 +02:00
|
|
|
if ((state.iaPatchVertexCount != 0) && (m_tcs == nullptr || m_tes == nullptr))
|
2018-03-21 15:22:18 +01:00
|
|
|
return false;
|
|
|
|
|
2018-01-12 14:25:26 +01:00
|
|
|
// No errors
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-01-16 15:00:19 +01:00
|
|
|
|
2018-02-07 16:44:30 +01:00
|
|
|
void DxvkGraphicsPipeline::logPipelineState(
|
2018-04-02 19:05:41 +02:00
|
|
|
LogLevel level,
|
2018-02-07 16:44:30 +01:00
|
|
|
const DxvkGraphicsPipelineStateInfo& state) const {
|
2018-05-03 20:26:55 +02:00
|
|
|
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()));
|
2018-02-07 16:44:30 +01:00
|
|
|
|
|
|
|
// TODO log more pipeline state
|
|
|
|
}
|
|
|
|
|
2017-10-15 13:02:59 +02:00
|
|
|
}
|