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 {
|
||||
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
|
||||
// uniform storage buffer.
|
||||
|
|
|
@ -23,11 +23,64 @@ namespace vulkan {
|
|||
|
||||
using xe::ui::vulkan::CheckResult;
|
||||
|
||||
PipelineCache::PipelineCache(RegisterFile* register_file,
|
||||
ui::vulkan::VulkanDevice* device)
|
||||
: register_file_(register_file), device_(*device) {}
|
||||
PipelineCache::PipelineCache(
|
||||
RegisterFile* register_file, ui::vulkan::VulkanDevice* 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() {
|
||||
vkDestroyPipelineLayout(device_, pipeline_layout_, nullptr);
|
||||
vkDestroyPipelineCache(device_, pipeline_cache_, nullptr);
|
||||
|
||||
// Destroy all shaders.
|
||||
for (auto it : shader_map_) {
|
||||
delete it.second;
|
||||
|
@ -88,13 +141,331 @@ bool PipelineCache::ConfigurePipeline(VkCommandBuffer command_buffer,
|
|||
VulkanShader* vertex_shader,
|
||||
VulkanShader* pixel_shader,
|
||||
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() {
|
||||
// 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) {
|
||||
uint32_t value = register_file_->values[register_name].u32;
|
||||
if (*dest == value) {
|
||||
|
|
|
@ -30,7 +30,9 @@ namespace vulkan {
|
|||
// including shaders, various blend/etc options, and input configuration.
|
||||
class PipelineCache {
|
||||
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();
|
||||
|
||||
// Loads a shader from the cache, possibly translating it.
|
||||
|
@ -48,26 +50,36 @@ class PipelineCache {
|
|||
VulkanShader* pixel_shader,
|
||||
PrimitiveType primitive_type);
|
||||
|
||||
// Currently configured pipeline layout, if any.
|
||||
VkPipelineLayout current_pipeline_layout() const { return nullptr; }
|
||||
// Pipeline layout shared by all pipelines.
|
||||
VkPipelineLayout pipeline_layout() const { return pipeline_layout_; }
|
||||
|
||||
// Clears all cached content.
|
||||
void ClearCache();
|
||||
|
||||
private:
|
||||
// TODO(benvanik): geometry shader cache.
|
||||
// TODO(benvanik): translated shader cache.
|
||||
// TODO(benvanik): pipeline layouts.
|
||||
// TODO(benvanik): pipeline cache.
|
||||
// Gets a geometry shader used to emulate the given primitive type.
|
||||
// Returns nullptr if the primitive doesn't need to be emulated.
|
||||
VkShaderModule GetGeometryShader(PrimitiveType primitive_type);
|
||||
|
||||
RegisterFile* register_file_ = nullptr;
|
||||
VkDevice device_ = nullptr;
|
||||
|
||||
// Reusable shader translator.
|
||||
SpirvShaderTranslator shader_translator_;
|
||||
// Disassembler used to get the SPIRV disasm. Only used in debug.
|
||||
xe::ui::spirv::SpirvDisassembler disassembler_;
|
||||
// All loaded shaders mapped by their guest hash key.
|
||||
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:
|
||||
enum class UpdateStatus {
|
||||
kCompatible,
|
||||
|
|
|
@ -542,7 +542,9 @@ const RenderState* RenderCache::BeginRenderPass(VkCommandBuffer command_buffer,
|
|||
return nullptr;
|
||||
}
|
||||
current_state_.render_pass = render_pass;
|
||||
current_state_.render_pass_handle = render_pass->handle;
|
||||
current_state_.framebuffer = framebuffer;
|
||||
current_state_.framebuffer_handle = framebuffer->handle;
|
||||
}
|
||||
if (!render_pass) {
|
||||
return nullptr;
|
||||
|
|
|
@ -69,8 +69,10 @@ struct RenderState {
|
|||
RenderConfiguration config;
|
||||
// Render pass (to be used with pipelines/etc).
|
||||
CachedRenderPass* render_pass = nullptr;
|
||||
VkRenderPass render_pass_handle = nullptr;
|
||||
// Target framebuffer bound to the render pass.
|
||||
CachedFramebuffer* framebuffer = nullptr;
|
||||
VkFramebuffer framebuffer_handle = nullptr;
|
||||
};
|
||||
|
||||
// Manages the virtualized EDRAM and the render target cache.
|
||||
|
|
|
@ -22,11 +22,57 @@ namespace vulkan {
|
|||
|
||||
using xe::ui::vulkan::CheckResult;
|
||||
|
||||
constexpr uint32_t kMaxTextureSamplers = 32;
|
||||
|
||||
TextureCache::TextureCache(RegisterFile* register_file,
|
||||
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() {
|
||||
// TODO(benvanik): caching.
|
||||
|
|
|
@ -26,6 +26,12 @@ class TextureCache {
|
|||
TextureCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
|
||||
~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): Resolve.
|
||||
// TODO(benvanik): ReadTexture.
|
||||
|
@ -36,6 +42,9 @@ class TextureCache {
|
|||
private:
|
||||
RegisterFile* register_file_ = nullptr;
|
||||
VkDevice device_ = nullptr;
|
||||
|
||||
VkDescriptorPool descriptor_pool_ = nullptr;
|
||||
VkDescriptorSetLayout texture_descriptor_set_layout_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
|
|
|
@ -69,9 +69,11 @@ bool VulkanCommandProcessor::SetupContext() {
|
|||
// Initialize the state machine caches.
|
||||
buffer_cache_ = std::make_unique<BufferCache>(register_file_, device_,
|
||||
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_);
|
||||
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;
|
||||
}
|
||||
|
@ -222,29 +224,12 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
return false;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// Pass registers to the shaders.
|
||||
if (!PopulateConstants(command_buffer, vertex_shader, pixel_shader)) {
|
||||
render_cache_->EndRenderPass();
|
||||
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).
|
||||
if (!PopulateIndexBuffer(command_buffer, index_buffer_info)) {
|
||||
render_cache_->EndRenderPass();
|
||||
|
@ -263,7 +248,6 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Actually issue the draw.
|
||||
if (!index_buffer_info) {
|
||||
// Auto-indexed draw.
|
||||
|
@ -282,7 +266,6 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
vkCmdDrawIndexed(command_buffer, index_count, instance_count, first_index,
|
||||
vertex_offset, first_instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
// End the rendering pass.
|
||||
render_cache_->EndRenderPass();
|
||||
|
@ -333,6 +316,34 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
|
|||
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(
|
||||
VkCommandBuffer command_buffer, IndexBufferInfo* index_buffer_info) {
|
||||
auto& regs = *register_file_;
|
||||
|
|
|
@ -66,6 +66,9 @@ class VulkanCommandProcessor : public CommandProcessor {
|
|||
|
||||
bool IssueDraw(PrimitiveType primitive_type, uint32_t index_count,
|
||||
IndexBufferInfo* index_buffer_info) override;
|
||||
bool PopulateConstants(VkCommandBuffer command_buffer,
|
||||
VulkanShader* vertex_shader,
|
||||
VulkanShader* pixel_shader);
|
||||
bool PopulateIndexBuffer(VkCommandBuffer command_buffer,
|
||||
IndexBufferInfo* index_buffer_info);
|
||||
bool PopulateVertexBuffers(VkCommandBuffer command_buffer,
|
||||
|
|
Loading…
Reference in New Issue