Skeleton leaky hacky hardcoded pipeline setup.
This commit is contained in:
parent
990b600f53
commit
97174dbe4d
|
@ -38,6 +38,9 @@ class BufferCache {
|
||||||
VkDescriptorSet constant_descriptor_set() const {
|
VkDescriptorSet constant_descriptor_set() const {
|
||||||
return transient_descriptor_set_;
|
return transient_descriptor_set_;
|
||||||
}
|
}
|
||||||
|
VkDescriptorSetLayout constant_descriptor_set_layout() const {
|
||||||
|
return descriptor_set_layout_;
|
||||||
|
}
|
||||||
|
|
||||||
// Uploads the constants specified in the register maps to the transient
|
// Uploads the constants specified in the register maps to the transient
|
||||||
// uniform storage buffer.
|
// uniform storage buffer.
|
||||||
|
|
|
@ -23,11 +23,64 @@ namespace vulkan {
|
||||||
|
|
||||||
using xe::ui::vulkan::CheckResult;
|
using xe::ui::vulkan::CheckResult;
|
||||||
|
|
||||||
PipelineCache::PipelineCache(RegisterFile* register_file,
|
PipelineCache::PipelineCache(
|
||||||
ui::vulkan::VulkanDevice* device)
|
RegisterFile* register_file, ui::vulkan::VulkanDevice* device,
|
||||||
: register_file_(register_file), device_(*device) {}
|
VkDescriptorSetLayout uniform_descriptor_set_layout,
|
||||||
|
VkDescriptorSetLayout texture_descriptor_set_layout)
|
||||||
|
: register_file_(register_file), device_(*device) {
|
||||||
|
// Initialize the shared driver pipeline cache.
|
||||||
|
// We'll likely want to serialize this and reuse it, if that proves to be
|
||||||
|
// useful. If the shaders are expensive and this helps we could do it per
|
||||||
|
// game, otherwise a single shared cache for render state/etc.
|
||||||
|
VkPipelineCacheCreateInfo pipeline_cache_info;
|
||||||
|
pipeline_cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
|
||||||
|
pipeline_cache_info.pNext = nullptr;
|
||||||
|
pipeline_cache_info.flags = 0;
|
||||||
|
pipeline_cache_info.initialDataSize = 0;
|
||||||
|
pipeline_cache_info.pInitialData = nullptr;
|
||||||
|
auto err = vkCreatePipelineCache(device_, &pipeline_cache_info, nullptr,
|
||||||
|
&pipeline_cache_);
|
||||||
|
CheckResult(err, "vkCreatePipelineCache");
|
||||||
|
|
||||||
|
// Descriptors used by the pipelines.
|
||||||
|
// These are the only ones we can ever bind.
|
||||||
|
VkDescriptorSetLayout set_layouts[] = {
|
||||||
|
// Per-draw constant register uniforms.
|
||||||
|
uniform_descriptor_set_layout,
|
||||||
|
// All texture bindings.
|
||||||
|
texture_descriptor_set_layout,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Push constants used for draw parameters.
|
||||||
|
// We need to keep these under 128b across all stages.
|
||||||
|
VkPushConstantRange push_constant_ranges[2];
|
||||||
|
push_constant_ranges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
push_constant_ranges[0].offset = 0;
|
||||||
|
push_constant_ranges[0].size = sizeof(float) * 16;
|
||||||
|
push_constant_ranges[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
push_constant_ranges[1].offset = sizeof(float) * 16;
|
||||||
|
push_constant_ranges[1].size = sizeof(int);
|
||||||
|
|
||||||
|
// Shared pipeline layout.
|
||||||
|
VkPipelineLayoutCreateInfo pipeline_layout_info;
|
||||||
|
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||||
|
pipeline_layout_info.pNext = nullptr;
|
||||||
|
pipeline_layout_info.flags = 0;
|
||||||
|
pipeline_layout_info.setLayoutCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(set_layouts));
|
||||||
|
pipeline_layout_info.pSetLayouts = set_layouts;
|
||||||
|
pipeline_layout_info.pushConstantRangeCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(push_constant_ranges));
|
||||||
|
pipeline_layout_info.pPushConstantRanges = push_constant_ranges;
|
||||||
|
err = vkCreatePipelineLayout(*device, &pipeline_layout_info, nullptr,
|
||||||
|
&pipeline_layout_);
|
||||||
|
CheckResult(err, "vkCreatePipelineLayout");
|
||||||
|
}
|
||||||
|
|
||||||
PipelineCache::~PipelineCache() {
|
PipelineCache::~PipelineCache() {
|
||||||
|
vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
|
||||||
|
vkDestroyPipelineCache(device_, pipeline_cache_, nullptr);
|
||||||
|
|
||||||
// Destroy all shaders.
|
// Destroy all shaders.
|
||||||
for (auto it : shader_map_) {
|
for (auto it : shader_map_) {
|
||||||
delete it.second;
|
delete it.second;
|
||||||
|
@ -88,13 +141,331 @@ bool PipelineCache::ConfigurePipeline(VkCommandBuffer command_buffer,
|
||||||
VulkanShader* vertex_shader,
|
VulkanShader* vertex_shader,
|
||||||
VulkanShader* pixel_shader,
|
VulkanShader* pixel_shader,
|
||||||
PrimitiveType primitive_type) {
|
PrimitiveType primitive_type) {
|
||||||
return false;
|
// Uh, yeah. This happened.
|
||||||
|
|
||||||
|
VkPipelineShaderStageCreateInfo pipeline_stages[3];
|
||||||
|
uint32_t pipeline_stage_count = 0;
|
||||||
|
auto& vertex_pipeline_stage = pipeline_stages[pipeline_stage_count++];
|
||||||
|
vertex_pipeline_stage.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
vertex_pipeline_stage.pNext = nullptr;
|
||||||
|
vertex_pipeline_stage.flags = 0;
|
||||||
|
vertex_pipeline_stage.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||||
|
vertex_pipeline_stage.module = vertex_shader->shader_module();
|
||||||
|
vertex_pipeline_stage.pName = "main";
|
||||||
|
vertex_pipeline_stage.pSpecializationInfo = nullptr;
|
||||||
|
auto geometry_shader = GetGeometryShader(primitive_type);
|
||||||
|
if (geometry_shader) {
|
||||||
|
auto& geometry_pipeline_stage = pipeline_stages[pipeline_stage_count++];
|
||||||
|
geometry_pipeline_stage.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
geometry_pipeline_stage.pNext = nullptr;
|
||||||
|
geometry_pipeline_stage.flags = 0;
|
||||||
|
geometry_pipeline_stage.stage = VK_SHADER_STAGE_GEOMETRY_BIT;
|
||||||
|
geometry_pipeline_stage.module = geometry_shader;
|
||||||
|
geometry_pipeline_stage.pName = "main";
|
||||||
|
geometry_pipeline_stage.pSpecializationInfo = nullptr;
|
||||||
|
}
|
||||||
|
auto& pixel_pipeline_stage = pipeline_stages[pipeline_stage_count++];
|
||||||
|
pixel_pipeline_stage.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||||
|
pixel_pipeline_stage.pNext = nullptr;
|
||||||
|
pixel_pipeline_stage.flags = 0;
|
||||||
|
pixel_pipeline_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
pixel_pipeline_stage.module = pixel_shader->shader_module();
|
||||||
|
pixel_pipeline_stage.pName = "main";
|
||||||
|
pixel_pipeline_stage.pSpecializationInfo = nullptr;
|
||||||
|
|
||||||
|
VkPipelineVertexInputStateCreateInfo vertex_state_info;
|
||||||
|
vertex_state_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
|
vertex_state_info.pNext = nullptr;
|
||||||
|
VkVertexInputBindingDescription vertex_binding_descrs[64];
|
||||||
|
uint32_t vertex_binding_count = 0;
|
||||||
|
VkVertexInputAttributeDescription vertex_attrib_descrs[64];
|
||||||
|
uint32_t vertex_attrib_count = 0;
|
||||||
|
for (const auto& vertex_binding : vertex_shader->vertex_bindings()) {
|
||||||
|
assert_true(vertex_binding_count < xe::countof(vertex_binding_descrs));
|
||||||
|
auto& vertex_binding_descr = vertex_binding_descrs[vertex_binding_count++];
|
||||||
|
vertex_binding_descr.binding = vertex_binding.binding_index;
|
||||||
|
vertex_binding_descr.stride = vertex_binding.stride_words * 4;
|
||||||
|
vertex_binding_descr.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
|
||||||
|
for (const auto& attrib : vertex_binding.attributes) {
|
||||||
|
assert_true(vertex_attrib_count < xe::countof(vertex_attrib_descrs));
|
||||||
|
auto& vertex_attrib_descr = vertex_attrib_descrs[vertex_attrib_count++];
|
||||||
|
vertex_attrib_descr.location = attrib.attrib_index;
|
||||||
|
vertex_attrib_descr.binding = vertex_binding.binding_index;
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_UNDEFINED;
|
||||||
|
vertex_attrib_descr.offset = attrib.fetch_instr.attributes.offset * 4;
|
||||||
|
|
||||||
|
bool is_signed = attrib.fetch_instr.attributes.is_signed;
|
||||||
|
bool is_integer = attrib.fetch_instr.attributes.is_integer;
|
||||||
|
switch (attrib.fetch_instr.attributes.data_format) {
|
||||||
|
case VertexFormat::k_8_8_8_8:
|
||||||
|
vertex_attrib_descr.format =
|
||||||
|
is_signed ? VK_FORMAT_R8G8B8A8_SNORM : VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_2_10_10_10:
|
||||||
|
vertex_attrib_descr.format = is_signed
|
||||||
|
? VK_FORMAT_A2R10G10B10_SNORM_PACK32
|
||||||
|
: VK_FORMAT_A2R10G10B10_UNORM_PACK32;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_10_11_11:
|
||||||
|
assert_always("unsupported?");
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_11_11_10:
|
||||||
|
assert_true(is_signed);
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_B10G11R11_UFLOAT_PACK32;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_16_16:
|
||||||
|
vertex_attrib_descr.format =
|
||||||
|
is_signed ? VK_FORMAT_R16G16_SNORM : VK_FORMAT_R16G16_UNORM;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_16_16_FLOAT:
|
||||||
|
vertex_attrib_descr.format =
|
||||||
|
is_signed ? VK_FORMAT_R16G16_SSCALED : VK_FORMAT_R16G16_USCALED;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_16_16_16_16:
|
||||||
|
vertex_attrib_descr.format = is_signed ? VK_FORMAT_R16G16B16A16_SNORM
|
||||||
|
: VK_FORMAT_R16G16B16A16_UNORM;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_16_16_16_16_FLOAT:
|
||||||
|
vertex_attrib_descr.format = is_signed
|
||||||
|
? VK_FORMAT_R16G16B16A16_SSCALED
|
||||||
|
: VK_FORMAT_R16G16B16A16_USCALED;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32:
|
||||||
|
vertex_attrib_descr.format =
|
||||||
|
is_signed ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32_32:
|
||||||
|
vertex_attrib_descr.format =
|
||||||
|
is_signed ? VK_FORMAT_R32G32_SINT : VK_FORMAT_R32G32_UINT;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32_32_32_32:
|
||||||
|
vertex_attrib_descr.format =
|
||||||
|
is_signed ? VK_FORMAT_R32G32B32A32_SINT : VK_FORMAT_R32_UINT;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32_FLOAT:
|
||||||
|
assert_true(is_signed);
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_R32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32_32_FLOAT:
|
||||||
|
assert_true(is_signed);
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_R32G32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32_32_32_FLOAT:
|
||||||
|
assert_true(is_signed);
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
break;
|
||||||
|
case VertexFormat::k_32_32_32_32_FLOAT:
|
||||||
|
assert_true(is_signed);
|
||||||
|
vertex_attrib_descr.format = VK_FORMAT_R32G32B32A32_SFLOAT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(attrib.fetch_instr.attributes.data_format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vertex_state_info.vertexBindingDescriptionCount = vertex_binding_count;
|
||||||
|
vertex_state_info.pVertexBindingDescriptions = vertex_binding_descrs;
|
||||||
|
vertex_state_info.vertexAttributeDescriptionCount = vertex_attrib_count;
|
||||||
|
vertex_state_info.pVertexAttributeDescriptions = vertex_attrib_descrs;
|
||||||
|
|
||||||
|
VkPipelineInputAssemblyStateCreateInfo input_info;
|
||||||
|
input_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||||
|
input_info.pNext = nullptr;
|
||||||
|
input_info.flags = 0;
|
||||||
|
input_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||||
|
input_info.primitiveRestartEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineViewportStateCreateInfo viewport_state_info;
|
||||||
|
viewport_state_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||||
|
viewport_state_info.pNext = nullptr;
|
||||||
|
viewport_state_info.flags = 0;
|
||||||
|
VkViewport viewport;
|
||||||
|
viewport.x = 0;
|
||||||
|
viewport.y = 0;
|
||||||
|
viewport.width = 100;
|
||||||
|
viewport.height = 100;
|
||||||
|
viewport.minDepth = 0;
|
||||||
|
viewport.maxDepth = 1;
|
||||||
|
viewport_state_info.viewportCount = 1;
|
||||||
|
viewport_state_info.pViewports = &viewport;
|
||||||
|
VkRect2D scissor;
|
||||||
|
scissor.offset.x = 0;
|
||||||
|
scissor.offset.y = 0;
|
||||||
|
scissor.extent.width = 100;
|
||||||
|
scissor.extent.height = 100;
|
||||||
|
viewport_state_info.scissorCount = 1;
|
||||||
|
viewport_state_info.pScissors = &scissor;
|
||||||
|
|
||||||
|
VkPipelineRasterizationStateCreateInfo rasterization_info;
|
||||||
|
rasterization_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||||
|
rasterization_info.pNext = nullptr;
|
||||||
|
rasterization_info.flags = 0;
|
||||||
|
rasterization_info.depthClampEnable = VK_FALSE;
|
||||||
|
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
|
||||||
|
rasterization_info.polygonMode = VK_POLYGON_MODE_FILL;
|
||||||
|
rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||||
|
rasterization_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||||
|
rasterization_info.depthBiasEnable = VK_FALSE;
|
||||||
|
rasterization_info.depthBiasConstantFactor = 0;
|
||||||
|
rasterization_info.depthBiasClamp = 0;
|
||||||
|
rasterization_info.depthBiasSlopeFactor = 0;
|
||||||
|
rasterization_info.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
VkPipelineMultisampleStateCreateInfo multisample_info;
|
||||||
|
multisample_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
multisample_info.pNext = nullptr;
|
||||||
|
multisample_info.flags = 0;
|
||||||
|
multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
|
multisample_info.sampleShadingEnable = VK_FALSE;
|
||||||
|
multisample_info.minSampleShading = 0;
|
||||||
|
multisample_info.pSampleMask = nullptr;
|
||||||
|
multisample_info.alphaToCoverageEnable = VK_FALSE;
|
||||||
|
multisample_info.alphaToOneEnable = VK_FALSE;
|
||||||
|
|
||||||
|
VkPipelineDepthStencilStateCreateInfo depth_stencil_info;
|
||||||
|
depth_stencil_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||||
|
depth_stencil_info.pNext = nullptr;
|
||||||
|
depth_stencil_info.flags = 0;
|
||||||
|
depth_stencil_info.depthTestEnable = VK_FALSE;
|
||||||
|
depth_stencil_info.depthWriteEnable = VK_FALSE;
|
||||||
|
depth_stencil_info.depthCompareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
depth_stencil_info.depthBoundsTestEnable = VK_FALSE;
|
||||||
|
depth_stencil_info.stencilTestEnable = VK_FALSE;
|
||||||
|
depth_stencil_info.front.failOp = VK_STENCIL_OP_KEEP;
|
||||||
|
depth_stencil_info.front.passOp = VK_STENCIL_OP_KEEP;
|
||||||
|
depth_stencil_info.front.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||||
|
depth_stencil_info.front.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
depth_stencil_info.front.compareMask = 0;
|
||||||
|
depth_stencil_info.front.writeMask = 0;
|
||||||
|
depth_stencil_info.front.reference = 0;
|
||||||
|
depth_stencil_info.back.failOp = VK_STENCIL_OP_KEEP;
|
||||||
|
depth_stencil_info.back.passOp = VK_STENCIL_OP_KEEP;
|
||||||
|
depth_stencil_info.back.depthFailOp = VK_STENCIL_OP_KEEP;
|
||||||
|
depth_stencil_info.back.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||||
|
depth_stencil_info.back.compareMask = 0;
|
||||||
|
depth_stencil_info.back.writeMask = 0;
|
||||||
|
depth_stencil_info.back.reference = 0;
|
||||||
|
depth_stencil_info.minDepthBounds = 0;
|
||||||
|
depth_stencil_info.maxDepthBounds = 0;
|
||||||
|
|
||||||
|
VkPipelineColorBlendStateCreateInfo blend_info;
|
||||||
|
blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||||
|
blend_info.pNext = nullptr;
|
||||||
|
blend_info.flags = 0;
|
||||||
|
blend_info.logicOpEnable = VK_FALSE;
|
||||||
|
blend_info.logicOp = VK_LOGIC_OP_NO_OP;
|
||||||
|
|
||||||
|
VkPipelineColorBlendAttachmentState blend_attachments[1];
|
||||||
|
blend_attachments[0].blendEnable = VK_TRUE;
|
||||||
|
blend_attachments[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
blend_attachments[0].dstColorBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blend_attachments[0].colorBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blend_attachments[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||||
|
blend_attachments[0].dstAlphaBlendFactor =
|
||||||
|
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||||
|
blend_attachments[0].alphaBlendOp = VK_BLEND_OP_ADD;
|
||||||
|
blend_attachments[0].colorWriteMask = 0xF;
|
||||||
|
blend_info.attachmentCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(blend_attachments));
|
||||||
|
blend_info.pAttachments = blend_attachments;
|
||||||
|
std::memset(blend_info.blendConstants, 0, sizeof(blend_info.blendConstants));
|
||||||
|
|
||||||
|
VkPipelineDynamicStateCreateInfo dynamic_state_info;
|
||||||
|
dynamic_state_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||||
|
dynamic_state_info.pNext = nullptr;
|
||||||
|
dynamic_state_info.flags = 0;
|
||||||
|
// VkDynamicState dynamic_states[] = {
|
||||||
|
// VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
||||||
|
//};
|
||||||
|
// dynamic_state_info.dynamicStateCount =
|
||||||
|
// static_cast<uint32_t>(xe::countof(dynamic_states));
|
||||||
|
// dynamic_state_info.pDynamicStates = dynamic_states;
|
||||||
|
dynamic_state_info.dynamicStateCount = 0;
|
||||||
|
dynamic_state_info.pDynamicStates = nullptr;
|
||||||
|
|
||||||
|
VkGraphicsPipelineCreateInfo pipeline_info;
|
||||||
|
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
|
pipeline_info.pNext = nullptr;
|
||||||
|
pipeline_info.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT;
|
||||||
|
pipeline_info.stageCount = pipeline_stage_count;
|
||||||
|
pipeline_info.pStages = pipeline_stages;
|
||||||
|
pipeline_info.pVertexInputState = &vertex_state_info;
|
||||||
|
pipeline_info.pInputAssemblyState = &input_info;
|
||||||
|
pipeline_info.pTessellationState = nullptr;
|
||||||
|
pipeline_info.pViewportState = &viewport_state_info;
|
||||||
|
pipeline_info.pRasterizationState = &rasterization_info;
|
||||||
|
pipeline_info.pMultisampleState = &multisample_info;
|
||||||
|
pipeline_info.pDepthStencilState = &depth_stencil_info;
|
||||||
|
pipeline_info.pColorBlendState = &blend_info;
|
||||||
|
pipeline_info.pDynamicState = &dynamic_state_info;
|
||||||
|
pipeline_info.layout = pipeline_layout_;
|
||||||
|
pipeline_info.renderPass = render_state->render_pass_handle;
|
||||||
|
pipeline_info.subpass = 0;
|
||||||
|
pipeline_info.basePipelineHandle = nullptr;
|
||||||
|
pipeline_info.basePipelineIndex = 0;
|
||||||
|
|
||||||
|
VkPipeline pipeline = nullptr;
|
||||||
|
auto err = vkCreateGraphicsPipelines(device_, nullptr, 1, &pipeline_info,
|
||||||
|
nullptr, &pipeline);
|
||||||
|
CheckResult(err, "vkCreateGraphicsPipelines");
|
||||||
|
|
||||||
|
// TODO(benvanik): don't leak pipelines >_>
|
||||||
|
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipelineCache::ClearCache() {
|
void PipelineCache::ClearCache() {
|
||||||
// TODO(benvanik): caching.
|
// TODO(benvanik): caching.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VkShaderModule PipelineCache::GetGeometryShader(PrimitiveType primitive_type) {
|
||||||
|
switch (primitive_type) {
|
||||||
|
case PrimitiveType::kLineList:
|
||||||
|
case PrimitiveType::kLineStrip:
|
||||||
|
case PrimitiveType::kTriangleList:
|
||||||
|
case PrimitiveType::kTriangleFan:
|
||||||
|
case PrimitiveType::kTriangleStrip:
|
||||||
|
// Supported directly - no need to emulate.
|
||||||
|
return nullptr;
|
||||||
|
case PrimitiveType::kPointList:
|
||||||
|
// TODO(benvanik): point list geometry shader.
|
||||||
|
return nullptr;
|
||||||
|
case PrimitiveType::kUnknown0x07:
|
||||||
|
assert_always("Unknown geometry type");
|
||||||
|
return nullptr;
|
||||||
|
case PrimitiveType::kRectangleList:
|
||||||
|
// TODO(benvanik): rectangle list geometry shader.
|
||||||
|
return nullptr;
|
||||||
|
case PrimitiveType::kLineLoop:
|
||||||
|
// TODO(benvanik): line loop geometry shader.
|
||||||
|
return nullptr;
|
||||||
|
case PrimitiveType::kQuadList:
|
||||||
|
// TODO(benvanik): quad list geometry shader.
|
||||||
|
return nullptr;
|
||||||
|
case PrimitiveType::kQuadStrip:
|
||||||
|
// TODO(benvanik): quad strip geometry shader.
|
||||||
|
return nullptr;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(primitive_type);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool PipelineCache::SetShadowRegister(uint32_t* dest, uint32_t register_name) {
|
bool PipelineCache::SetShadowRegister(uint32_t* dest, uint32_t register_name) {
|
||||||
uint32_t value = register_file_->values[register_name].u32;
|
uint32_t value = register_file_->values[register_name].u32;
|
||||||
if (*dest == value) {
|
if (*dest == value) {
|
||||||
|
|
|
@ -30,7 +30,9 @@ namespace vulkan {
|
||||||
// including shaders, various blend/etc options, and input configuration.
|
// including shaders, various blend/etc options, and input configuration.
|
||||||
class PipelineCache {
|
class PipelineCache {
|
||||||
public:
|
public:
|
||||||
PipelineCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
|
PipelineCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device,
|
||||||
|
VkDescriptorSetLayout uniform_descriptor_set_layout,
|
||||||
|
VkDescriptorSetLayout texture_descriptor_set_layout);
|
||||||
~PipelineCache();
|
~PipelineCache();
|
||||||
|
|
||||||
// Loads a shader from the cache, possibly translating it.
|
// Loads a shader from the cache, possibly translating it.
|
||||||
|
@ -48,26 +50,36 @@ class PipelineCache {
|
||||||
VulkanShader* pixel_shader,
|
VulkanShader* pixel_shader,
|
||||||
PrimitiveType primitive_type);
|
PrimitiveType primitive_type);
|
||||||
|
|
||||||
// Currently configured pipeline layout, if any.
|
// Pipeline layout shared by all pipelines.
|
||||||
VkPipelineLayout current_pipeline_layout() const { return nullptr; }
|
VkPipelineLayout pipeline_layout() const { return pipeline_layout_; }
|
||||||
|
|
||||||
// Clears all cached content.
|
// Clears all cached content.
|
||||||
void ClearCache();
|
void ClearCache();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// TODO(benvanik): geometry shader cache.
|
// Gets a geometry shader used to emulate the given primitive type.
|
||||||
// TODO(benvanik): translated shader cache.
|
// Returns nullptr if the primitive doesn't need to be emulated.
|
||||||
// TODO(benvanik): pipeline layouts.
|
VkShaderModule GetGeometryShader(PrimitiveType primitive_type);
|
||||||
// TODO(benvanik): pipeline cache.
|
|
||||||
|
|
||||||
RegisterFile* register_file_ = nullptr;
|
RegisterFile* register_file_ = nullptr;
|
||||||
VkDevice device_ = nullptr;
|
VkDevice device_ = nullptr;
|
||||||
|
|
||||||
|
// Reusable shader translator.
|
||||||
SpirvShaderTranslator shader_translator_;
|
SpirvShaderTranslator shader_translator_;
|
||||||
|
// Disassembler used to get the SPIRV disasm. Only used in debug.
|
||||||
xe::ui::spirv::SpirvDisassembler disassembler_;
|
xe::ui::spirv::SpirvDisassembler disassembler_;
|
||||||
// All loaded shaders mapped by their guest hash key.
|
// All loaded shaders mapped by their guest hash key.
|
||||||
std::unordered_map<uint64_t, VulkanShader*> shader_map_;
|
std::unordered_map<uint64_t, VulkanShader*> shader_map_;
|
||||||
|
|
||||||
|
// Vulkan pipeline cache, which in theory helps us out.
|
||||||
|
// This can be serialized to disk and reused, if we want.
|
||||||
|
VkPipelineCache pipeline_cache_ = nullptr;
|
||||||
|
// Layout used for all pipelines describing our uniforms, textures, and push
|
||||||
|
// constants.
|
||||||
|
VkPipelineLayout pipeline_layout_ = nullptr;
|
||||||
|
|
||||||
|
// TODO(benvanik): geometry shader cache.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class UpdateStatus {
|
enum class UpdateStatus {
|
||||||
kCompatible,
|
kCompatible,
|
||||||
|
|
|
@ -542,7 +542,9 @@ const RenderState* RenderCache::BeginRenderPass(VkCommandBuffer command_buffer,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
current_state_.render_pass = render_pass;
|
current_state_.render_pass = render_pass;
|
||||||
|
current_state_.render_pass_handle = render_pass->handle;
|
||||||
current_state_.framebuffer = framebuffer;
|
current_state_.framebuffer = framebuffer;
|
||||||
|
current_state_.framebuffer_handle = framebuffer->handle;
|
||||||
}
|
}
|
||||||
if (!render_pass) {
|
if (!render_pass) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -69,8 +69,10 @@ struct RenderState {
|
||||||
RenderConfiguration config;
|
RenderConfiguration config;
|
||||||
// Render pass (to be used with pipelines/etc).
|
// Render pass (to be used with pipelines/etc).
|
||||||
CachedRenderPass* render_pass = nullptr;
|
CachedRenderPass* render_pass = nullptr;
|
||||||
|
VkRenderPass render_pass_handle = nullptr;
|
||||||
// Target framebuffer bound to the render pass.
|
// Target framebuffer bound to the render pass.
|
||||||
CachedFramebuffer* framebuffer = nullptr;
|
CachedFramebuffer* framebuffer = nullptr;
|
||||||
|
VkFramebuffer framebuffer_handle = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Manages the virtualized EDRAM and the render target cache.
|
// Manages the virtualized EDRAM and the render target cache.
|
||||||
|
|
|
@ -22,11 +22,57 @@ namespace vulkan {
|
||||||
|
|
||||||
using xe::ui::vulkan::CheckResult;
|
using xe::ui::vulkan::CheckResult;
|
||||||
|
|
||||||
|
constexpr uint32_t kMaxTextureSamplers = 32;
|
||||||
|
|
||||||
TextureCache::TextureCache(RegisterFile* register_file,
|
TextureCache::TextureCache(RegisterFile* register_file,
|
||||||
ui::vulkan::VulkanDevice* device)
|
ui::vulkan::VulkanDevice* device)
|
||||||
: register_file_(register_file), device_(*device) {}
|
: register_file_(register_file), device_(*device) {
|
||||||
|
// Descriptor pool used for all of our cached descriptors.
|
||||||
|
VkDescriptorPoolCreateInfo descriptor_pool_info;
|
||||||
|
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||||
|
descriptor_pool_info.pNext = nullptr;
|
||||||
|
descriptor_pool_info.flags =
|
||||||
|
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||||
|
descriptor_pool_info.maxSets = 256;
|
||||||
|
VkDescriptorPoolSize pool_sizes[1];
|
||||||
|
pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
|
pool_sizes[0].descriptorCount = 256;
|
||||||
|
descriptor_pool_info.poolSizeCount = 1;
|
||||||
|
descriptor_pool_info.pPoolSizes = pool_sizes;
|
||||||
|
auto err = vkCreateDescriptorPool(device_, &descriptor_pool_info, nullptr,
|
||||||
|
&descriptor_pool_);
|
||||||
|
CheckResult(err, "vkCreateDescriptorPool");
|
||||||
|
|
||||||
TextureCache::~TextureCache() = default;
|
// Create the descriptor set layout used for rendering.
|
||||||
|
// We always have the same number of samplers but only some are used.
|
||||||
|
VkDescriptorSetLayoutBinding texture_bindings[1];
|
||||||
|
for (int i = 0; i < 1; ++i) {
|
||||||
|
auto& texture_binding = texture_bindings[i];
|
||||||
|
texture_binding.binding = 0;
|
||||||
|
texture_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
|
||||||
|
texture_binding.descriptorCount = kMaxTextureSamplers;
|
||||||
|
texture_binding.stageFlags =
|
||||||
|
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
|
texture_binding.pImmutableSamplers = nullptr;
|
||||||
|
}
|
||||||
|
VkDescriptorSetLayoutCreateInfo descriptor_set_layout_info;
|
||||||
|
descriptor_set_layout_info.sType =
|
||||||
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||||
|
descriptor_set_layout_info.pNext = nullptr;
|
||||||
|
descriptor_set_layout_info.flags = 0;
|
||||||
|
descriptor_set_layout_info.bindingCount =
|
||||||
|
static_cast<uint32_t>(xe::countof(texture_bindings));
|
||||||
|
descriptor_set_layout_info.pBindings = texture_bindings;
|
||||||
|
err = vkCreateDescriptorSetLayout(device_, &descriptor_set_layout_info,
|
||||||
|
nullptr, &texture_descriptor_set_layout_);
|
||||||
|
CheckResult(err, "vkCreateDescriptorSetLayout");
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureCache::~TextureCache() {
|
||||||
|
vkDestroyDescriptorSetLayout(device_, texture_descriptor_set_layout_,
|
||||||
|
nullptr);
|
||||||
|
vkDestroyDescriptorPool(device_, descriptor_pool_, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void TextureCache::ClearCache() {
|
void TextureCache::ClearCache() {
|
||||||
// TODO(benvanik): caching.
|
// TODO(benvanik): caching.
|
||||||
|
|
|
@ -26,6 +26,12 @@ class TextureCache {
|
||||||
TextureCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
|
TextureCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
|
||||||
~TextureCache();
|
~TextureCache();
|
||||||
|
|
||||||
|
// Descriptor set layout containing all possible texture bindings.
|
||||||
|
// The set contains one descriptor for each texture sampler [0-31].
|
||||||
|
VkDescriptorSetLayout texture_descriptor_set_layout() const {
|
||||||
|
return texture_descriptor_set_layout_;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(benvanik): UploadTexture.
|
// TODO(benvanik): UploadTexture.
|
||||||
// TODO(benvanik): Resolve.
|
// TODO(benvanik): Resolve.
|
||||||
// TODO(benvanik): ReadTexture.
|
// TODO(benvanik): ReadTexture.
|
||||||
|
@ -36,6 +42,9 @@ class TextureCache {
|
||||||
private:
|
private:
|
||||||
RegisterFile* register_file_ = nullptr;
|
RegisterFile* register_file_ = nullptr;
|
||||||
VkDevice device_ = nullptr;
|
VkDevice device_ = nullptr;
|
||||||
|
|
||||||
|
VkDescriptorPool descriptor_pool_ = nullptr;
|
||||||
|
VkDescriptorSetLayout texture_descriptor_set_layout_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vulkan
|
} // namespace vulkan
|
||||||
|
|
|
@ -69,9 +69,11 @@ bool VulkanCommandProcessor::SetupContext() {
|
||||||
// Initialize the state machine caches.
|
// Initialize the state machine caches.
|
||||||
buffer_cache_ = std::make_unique<BufferCache>(register_file_, device_,
|
buffer_cache_ = std::make_unique<BufferCache>(register_file_, device_,
|
||||||
kDefaultBufferCacheCapacity);
|
kDefaultBufferCacheCapacity);
|
||||||
pipeline_cache_ = std::make_unique<PipelineCache>(register_file_, device_);
|
|
||||||
render_cache_ = std::make_unique<RenderCache>(register_file_, device_);
|
|
||||||
texture_cache_ = std::make_unique<TextureCache>(register_file_, device_);
|
texture_cache_ = std::make_unique<TextureCache>(register_file_, device_);
|
||||||
|
pipeline_cache_ = std::make_unique<PipelineCache>(
|
||||||
|
register_file_, device_, buffer_cache_->constant_descriptor_set_layout(),
|
||||||
|
texture_cache_->texture_descriptor_set_layout());
|
||||||
|
render_cache_ = std::make_unique<RenderCache>(register_file_, device_);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -222,29 +224,12 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Upload the constants the shaders require.
|
// Pass registers to the shaders.
|
||||||
// These are optional, and if none are defined 0 will be returned.
|
if (!PopulateConstants(command_buffer, vertex_shader, pixel_shader)) {
|
||||||
VkDeviceSize vertex_constant_offset = buffer_cache_->UploadConstantRegisters(
|
|
||||||
vertex_shader->constant_register_map());
|
|
||||||
VkDeviceSize pixel_constant_offset = buffer_cache_->UploadConstantRegisters(
|
|
||||||
pixel_shader->constant_register_map());
|
|
||||||
if (vertex_constant_offset == VK_WHOLE_SIZE ||
|
|
||||||
pixel_constant_offset == VK_WHOLE_SIZE) {
|
|
||||||
// Shader wants constants but we couldn't upload them.
|
|
||||||
render_cache_->EndRenderPass();
|
render_cache_->EndRenderPass();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure constant uniform access to point at our offsets.
|
|
||||||
auto constant_descriptor_set = buffer_cache_->constant_descriptor_set();
|
|
||||||
auto pipeline_layout = pipeline_cache_->current_pipeline_layout();
|
|
||||||
uint32_t constant_offsets[2] = {static_cast<uint32_t>(vertex_constant_offset),
|
|
||||||
static_cast<uint32_t>(pixel_constant_offset)};
|
|
||||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
||||||
pipeline_layout, 0, 1, &constant_descriptor_set,
|
|
||||||
static_cast<uint32_t>(xe::countof(constant_offsets)),
|
|
||||||
constant_offsets);
|
|
||||||
|
|
||||||
// Upload and bind index buffer data (if we have any).
|
// Upload and bind index buffer data (if we have any).
|
||||||
if (!PopulateIndexBuffer(command_buffer, index_buffer_info)) {
|
if (!PopulateIndexBuffer(command_buffer, index_buffer_info)) {
|
||||||
render_cache_->EndRenderPass();
|
render_cache_->EndRenderPass();
|
||||||
|
@ -263,7 +248,6 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Actually issue the draw.
|
// Actually issue the draw.
|
||||||
if (!index_buffer_info) {
|
if (!index_buffer_info) {
|
||||||
// Auto-indexed draw.
|
// Auto-indexed draw.
|
||||||
|
@ -282,7 +266,6 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||||
vkCmdDrawIndexed(command_buffer, index_count, instance_count, first_index,
|
vkCmdDrawIndexed(command_buffer, index_count, instance_count, first_index,
|
||||||
vertex_offset, first_instance);
|
vertex_offset, first_instance);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// End the rendering pass.
|
// End the rendering pass.
|
||||||
render_cache_->EndRenderPass();
|
render_cache_->EndRenderPass();
|
||||||
|
@ -333,6 +316,34 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VulkanCommandProcessor::PopulateConstants(VkCommandBuffer command_buffer,
|
||||||
|
VulkanShader* vertex_shader,
|
||||||
|
VulkanShader* pixel_shader) {
|
||||||
|
// Upload the constants the shaders require.
|
||||||
|
// These are optional, and if none are defined 0 will be returned.
|
||||||
|
VkDeviceSize vertex_constant_offset = buffer_cache_->UploadConstantRegisters(
|
||||||
|
vertex_shader->constant_register_map());
|
||||||
|
VkDeviceSize pixel_constant_offset = buffer_cache_->UploadConstantRegisters(
|
||||||
|
pixel_shader->constant_register_map());
|
||||||
|
if (vertex_constant_offset == VK_WHOLE_SIZE ||
|
||||||
|
pixel_constant_offset == VK_WHOLE_SIZE) {
|
||||||
|
// Shader wants constants but we couldn't upload them.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure constant uniform access to point at our offsets.
|
||||||
|
auto constant_descriptor_set = buffer_cache_->constant_descriptor_set();
|
||||||
|
auto pipeline_layout = pipeline_cache_->pipeline_layout();
|
||||||
|
uint32_t constant_offsets[2] = {static_cast<uint32_t>(vertex_constant_offset),
|
||||||
|
static_cast<uint32_t>(pixel_constant_offset)};
|
||||||
|
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||||
|
pipeline_layout, 0, 1, &constant_descriptor_set,
|
||||||
|
static_cast<uint32_t>(xe::countof(constant_offsets)),
|
||||||
|
constant_offsets);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool VulkanCommandProcessor::PopulateIndexBuffer(
|
bool VulkanCommandProcessor::PopulateIndexBuffer(
|
||||||
VkCommandBuffer command_buffer, IndexBufferInfo* index_buffer_info) {
|
VkCommandBuffer command_buffer, IndexBufferInfo* index_buffer_info) {
|
||||||
auto& regs = *register_file_;
|
auto& regs = *register_file_;
|
||||||
|
|
|
@ -66,6 +66,9 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||||
|
|
||||||
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
|
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
|
||||||
IndexBufferInfo* index_buffer_info) override;
|
IndexBufferInfo* index_buffer_info) override;
|
||||||
|
bool PopulateConstants(VkCommandBuffer command_buffer,
|
||||||
|
VulkanShader* vertex_shader,
|
||||||
|
VulkanShader* pixel_shader);
|
||||||
bool PopulateIndexBuffer(VkCommandBuffer command_buffer,
|
bool PopulateIndexBuffer(VkCommandBuffer command_buffer,
|
||||||
IndexBufferInfo* index_buffer_info);
|
IndexBufferInfo* index_buffer_info);
|
||||||
bool PopulateVertexBuffers(VkCommandBuffer command_buffer,
|
bool PopulateVertexBuffers(VkCommandBuffer command_buffer,
|
||||||
|
|
Loading…
Reference in New Issue