Skeleton leaky hacky hardcoded pipeline setup.

This commit is contained in:
Ben Vanik 2016-02-19 23:23:58 -08:00
parent 990b600f53
commit 97174dbe4d
9 changed files with 495 additions and 36 deletions

View File

@ -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.

View File

@ -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) {

View File

@ -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,

View File

@ -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;

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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_;

View 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,