From 52a6f795f76f4b1c7bc053d8c7aae8bc26d3958a Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Thu, 18 Feb 2016 18:18:00 -0800 Subject: [PATCH] Shader modules and plumbing. --- src/xenia/gpu/vulkan/pipeline_cache.cc | 6 ++- src/xenia/gpu/vulkan/pipeline_cache.h | 7 +--- src/xenia/gpu/vulkan/render_cache.cc | 16 ++++++-- src/xenia/gpu/vulkan/render_cache.h | 23 ++++++++++-- src/xenia/gpu/vulkan/texture_cache.h | 4 +- .../gpu/vulkan/vulkan_command_processor.cc | 16 ++++++-- src/xenia/gpu/vulkan/vulkan_gpu_flags.h | 2 + src/xenia/gpu/vulkan/vulkan_shader.cc | 37 ++++++++++++++++--- src/xenia/gpu/vulkan/vulkan_shader.h | 4 +- 9 files changed, 89 insertions(+), 26 deletions(-) diff --git a/src/xenia/gpu/vulkan/pipeline_cache.cc b/src/xenia/gpu/vulkan/pipeline_cache.cc index e09931833..ec6c28eac 100644 --- a/src/xenia/gpu/vulkan/pipeline_cache.cc +++ b/src/xenia/gpu/vulkan/pipeline_cache.cc @@ -50,8 +50,8 @@ VulkanShader* PipelineCache::LoadShader(ShaderType shader_type, // Always create the shader and stash it away. // We need to track it even if it fails translation so we know not to try // again. - VulkanShader* shader = - new VulkanShader(shader_type, data_hash, host_address, dword_count); + VulkanShader* shader = new VulkanShader(device_, shader_type, data_hash, + host_address, dword_count); shader_map_.insert({data_hash, shader}); // Perform translation. @@ -85,6 +85,8 @@ VulkanShader* PipelineCache::LoadShader(ShaderType shader_type, bool PipelineCache::ConfigurePipeline(VkCommandBuffer command_buffer, VkRenderPass render_pass, + VulkanShader* vertex_shader, + VulkanShader* pixel_shader, PrimitiveType primitive_type) { return false; } diff --git a/src/xenia/gpu/vulkan/pipeline_cache.h b/src/xenia/gpu/vulkan/pipeline_cache.h index 56727e67a..00e36ef12 100644 --- a/src/xenia/gpu/vulkan/pipeline_cache.h +++ b/src/xenia/gpu/vulkan/pipeline_cache.h @@ -42,15 +42,12 @@ class PipelineCache { // in the command buffer is issued at this time. // Returns whether the pipeline could be successfully created. bool ConfigurePipeline(VkCommandBuffer command_buffer, - VkRenderPass render_pass, + VkRenderPass render_pass, VulkanShader* vertex_shader, + VulkanShader* pixel_shader, PrimitiveType primitive_type); // Currently configured pipeline layout, if any. VkPipelineLayout current_pipeline_layout() const { return nullptr; } - // Currently configured vertex shader, if any. - VulkanShader* current_vertex_shader() const { return nullptr; } - // Currently configured pixel shader, if any. - VulkanShader* current_pixel_shader() const { return nullptr; } // Clears all cached content. void ClearCache(); diff --git a/src/xenia/gpu/vulkan/render_cache.cc b/src/xenia/gpu/vulkan/render_cache.cc index fef05f11f..de25fb2e3 100644 --- a/src/xenia/gpu/vulkan/render_cache.cc +++ b/src/xenia/gpu/vulkan/render_cache.cc @@ -28,12 +28,22 @@ RenderCache::RenderCache(RegisterFile* register_file, RenderCache::~RenderCache() = default; -VkRenderPass RenderCache::BeginRenderPass(VkCommandBuffer command_buffer) { - return nullptr; +VkRenderPass RenderCache::BeginRenderPass(VkCommandBuffer command_buffer, + VulkanShader* vertex_shader, + VulkanShader* pixel_shader) { + assert_null(current_command_buffer_); + current_command_buffer_ = command_buffer; + + // Lookup or construct a render pass compatible with our current state. + VkRenderPass render_pass = nullptr; + + return render_pass; } void RenderCache::EndRenderPass() { - // + assert_not_null(current_command_buffer_); + auto command_buffer = current_command_buffer_; + current_command_buffer_ = nullptr; } void RenderCache::ClearCache() { diff --git a/src/xenia/gpu/vulkan/render_cache.h b/src/xenia/gpu/vulkan/render_cache.h index fb7c84e6a..ceeea2a07 100644 --- a/src/xenia/gpu/vulkan/render_cache.h +++ b/src/xenia/gpu/vulkan/render_cache.h @@ -12,6 +12,7 @@ #include "xenia/gpu/register_file.h" #include "xenia/gpu/shader.h" +#include "xenia/gpu/vulkan/vulkan_shader.h" #include "xenia/gpu/xenos.h" #include "xenia/ui/vulkan/vulkan.h" #include "xenia/ui/vulkan/vulkan_device.h" @@ -20,15 +21,29 @@ namespace xe { namespace gpu { namespace vulkan { -// Configures and caches pipelines based on render state. -// This is responsible for properly setting all state required for a draw -// including shaders, various blend/etc options, and input configuration. +// Manages the virtualized EDRAM and the render target cache. +// +// On the 360 the render target is an opaque block of memory in EDRAM that's +// only accessible via resolves. We use this to our advantage to simulate +// something like it as best we can by having a shared backing memory with +// a multitude of views for each tile location in EDRAM. +// +// This allows us to have the same base address write to the same memory +// regardless of framebuffer format. Resolving then uses whatever format the +// resolve requests straight from the backing memory. class RenderCache { public: RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device); ~RenderCache(); - VkRenderPass BeginRenderPass(VkCommandBuffer command_buffer); + // Begins a render pass targeting the state-specified framebuffer formats. + // The command buffer will be transitioned into the render pass phase. + VkRenderPass BeginRenderPass(VkCommandBuffer command_buffer, + VulkanShader* vertex_shader, + VulkanShader* pixel_shader); + + // Ends the current render pass. + // The command buffer will be transitioned out of the render pass phase. void EndRenderPass(); // Clears all cached content. diff --git a/src/xenia/gpu/vulkan/texture_cache.h b/src/xenia/gpu/vulkan/texture_cache.h index 3545fb72d..3f18a7be1 100644 --- a/src/xenia/gpu/vulkan/texture_cache.h +++ b/src/xenia/gpu/vulkan/texture_cache.h @@ -20,9 +20,7 @@ namespace xe { namespace gpu { namespace vulkan { -// Configures and caches pipelines based on render state. -// This is responsible for properly setting all state required for a draw -// including shaders, various blend/etc options, and input configuration. +// class TextureCache { public: TextureCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device); diff --git a/src/xenia/gpu/vulkan/vulkan_command_processor.cc b/src/xenia/gpu/vulkan/vulkan_command_processor.cc index 6490de44a..8047bd202 100644 --- a/src/xenia/gpu/vulkan/vulkan_command_processor.cc +++ b/src/xenia/gpu/vulkan/vulkan_command_processor.cc @@ -175,6 +175,16 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type, return IssueCopy(); } + // Shaders will have already been defined by previous loads. + // We need the to do just about anything so validate here. + auto vertex_shader = static_cast(active_vertex_shader()); + auto pixel_shader = static_cast(active_pixel_shader()); + if (!vertex_shader || !vertex_shader->is_valid() || !pixel_shader || + !pixel_shader->is_valid()) { + // Skipped because we can't understand the shader. + return true; + } + // TODO(benvanik): bigger batches. command_buffer_pool_->BeginBatch(); VkCommandBuffer command_buffer = command_buffer_pool_->AcquireEntry(); @@ -188,7 +198,8 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type, // Begin the render pass. // This will setup our framebuffer and begin the pass in the command buffer. - VkRenderPass render_pass = render_cache_->BeginRenderPass(command_buffer); + VkRenderPass render_pass = render_cache_->BeginRenderPass( + command_buffer, vertex_shader, pixel_shader); if (!render_pass) { return false; } @@ -197,14 +208,13 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type, // This encodes all render state (blend, depth, etc), our shader stages, // and our vertex input layout. if (!pipeline_cache_->ConfigurePipeline(command_buffer, render_pass, + vertex_shader, pixel_shader, primitive_type)) { render_cache_->EndRenderPass(); return false; } // Upload the constants the shaders require. - auto vertex_shader = pipeline_cache_->current_vertex_shader(); - auto pixel_shader = pipeline_cache_->current_pixel_shader(); auto vertex_constant_offset = buffer_cache_->UploadConstantRegisters( vertex_shader->constant_register_map()); auto pixel_constant_offset = buffer_cache_->UploadConstantRegisters( diff --git a/src/xenia/gpu/vulkan/vulkan_gpu_flags.h b/src/xenia/gpu/vulkan/vulkan_gpu_flags.h index c78637a47..b5a00c74a 100644 --- a/src/xenia/gpu/vulkan/vulkan_gpu_flags.h +++ b/src/xenia/gpu/vulkan/vulkan_gpu_flags.h @@ -12,4 +12,6 @@ #include +#define FINE_GRAINED_DRAW_SCOPES 1 + #endif // XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_ diff --git a/src/xenia/gpu/vulkan/vulkan_shader.cc b/src/xenia/gpu/vulkan/vulkan_shader.cc index 8624480a3..b3c72abf3 100644 --- a/src/xenia/gpu/vulkan/vulkan_shader.cc +++ b/src/xenia/gpu/vulkan/vulkan_shader.cc @@ -9,20 +9,47 @@ #include "xenia/gpu/vulkan/vulkan_shader.h" +#include "xenia/base/assert.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" +#include "xenia/ui/vulkan/vulkan_util.h" namespace xe { namespace gpu { namespace vulkan { -VulkanShader::VulkanShader(ShaderType shader_type, uint64_t data_hash, - const uint32_t* dword_ptr, uint32_t dword_count) - : Shader(shader_type, data_hash, dword_ptr, dword_count) {} +using xe::ui::vulkan::CheckResult; -VulkanShader::~VulkanShader() = default; +VulkanShader::VulkanShader(VkDevice device, ShaderType shader_type, + uint64_t data_hash, const uint32_t* dword_ptr, + uint32_t dword_count) + : Shader(shader_type, data_hash, dword_ptr, dword_count), device_(device) {} -bool VulkanShader::Prepare() { return true; } +VulkanShader::~VulkanShader() { + if (shader_module_) { + vkDestroyShaderModule(device_, shader_module_, nullptr); + shader_module_ = nullptr; + } +} + +bool VulkanShader::Prepare() { + assert_null(shader_module_); + assert_true(is_valid()); + + // Create the shader module. + VkShaderModuleCreateInfo shader_info; + shader_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shader_info.pNext = nullptr; + shader_info.flags = 0; + shader_info.codeSize = translated_binary_.size(); + shader_info.pCode = + reinterpret_cast(translated_binary_.data()); + auto err = + vkCreateShaderModule(device_, &shader_info, nullptr, &shader_module_); + CheckResult(err, "vkCreateShaderModule"); + + return true; +} } // namespace vulkan } // namespace gpu diff --git a/src/xenia/gpu/vulkan/vulkan_shader.h b/src/xenia/gpu/vulkan/vulkan_shader.h index cc1d51e2a..97dbd5822 100644 --- a/src/xenia/gpu/vulkan/vulkan_shader.h +++ b/src/xenia/gpu/vulkan/vulkan_shader.h @@ -21,15 +21,17 @@ namespace vulkan { class VulkanShader : public Shader { public: - VulkanShader(ShaderType shader_type, uint64_t data_hash, + VulkanShader(VkDevice device, ShaderType shader_type, uint64_t data_hash, const uint32_t* dword_ptr, uint32_t dword_count); ~VulkanShader() override; + // Available only if the shader is_valid and has been prepared. VkShaderModule shader_module() const { return shader_module_; } bool Prepare(); private: + VkDevice device_ = nullptr; VkShaderModule shader_module_ = nullptr; };