Shader modules and plumbing.

This commit is contained in:
Ben Vanik 2016-02-18 18:18:00 -08:00
parent e14b2fe766
commit 52a6f795f7
9 changed files with 89 additions and 26 deletions

View File

@ -50,8 +50,8 @@ VulkanShader* PipelineCache::LoadShader(ShaderType shader_type,
// Always create the shader and stash it away. // Always create the shader and stash it away.
// We need to track it even if it fails translation so we know not to try // We need to track it even if it fails translation so we know not to try
// again. // again.
VulkanShader* shader = VulkanShader* shader = new VulkanShader(device_, shader_type, data_hash,
new VulkanShader(shader_type, data_hash, host_address, dword_count); host_address, dword_count);
shader_map_.insert({data_hash, shader}); shader_map_.insert({data_hash, shader});
// Perform translation. // Perform translation.
@ -85,6 +85,8 @@ VulkanShader* PipelineCache::LoadShader(ShaderType shader_type,
bool PipelineCache::ConfigurePipeline(VkCommandBuffer command_buffer, bool PipelineCache::ConfigurePipeline(VkCommandBuffer command_buffer,
VkRenderPass render_pass, VkRenderPass render_pass,
VulkanShader* vertex_shader,
VulkanShader* pixel_shader,
PrimitiveType primitive_type) { PrimitiveType primitive_type) {
return false; return false;
} }

View File

@ -42,15 +42,12 @@ class PipelineCache {
// in the command buffer is issued at this time. // in the command buffer is issued at this time.
// Returns whether the pipeline could be successfully created. // Returns whether the pipeline could be successfully created.
bool ConfigurePipeline(VkCommandBuffer command_buffer, bool ConfigurePipeline(VkCommandBuffer command_buffer,
VkRenderPass render_pass, VkRenderPass render_pass, VulkanShader* vertex_shader,
VulkanShader* pixel_shader,
PrimitiveType primitive_type); PrimitiveType primitive_type);
// Currently configured pipeline layout, if any. // Currently configured pipeline layout, if any.
VkPipelineLayout current_pipeline_layout() const { return nullptr; } 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. // Clears all cached content.
void ClearCache(); void ClearCache();

View File

@ -28,12 +28,22 @@ RenderCache::RenderCache(RegisterFile* register_file,
RenderCache::~RenderCache() = default; RenderCache::~RenderCache() = default;
VkRenderPass RenderCache::BeginRenderPass(VkCommandBuffer command_buffer) { VkRenderPass RenderCache::BeginRenderPass(VkCommandBuffer command_buffer,
return nullptr; 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() { void RenderCache::EndRenderPass() {
// assert_not_null(current_command_buffer_);
auto command_buffer = current_command_buffer_;
current_command_buffer_ = nullptr;
} }
void RenderCache::ClearCache() { void RenderCache::ClearCache() {

View File

@ -12,6 +12,7 @@
#include "xenia/gpu/register_file.h" #include "xenia/gpu/register_file.h"
#include "xenia/gpu/shader.h" #include "xenia/gpu/shader.h"
#include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/gpu/xenos.h" #include "xenia/gpu/xenos.h"
#include "xenia/ui/vulkan/vulkan.h" #include "xenia/ui/vulkan/vulkan.h"
#include "xenia/ui/vulkan/vulkan_device.h" #include "xenia/ui/vulkan/vulkan_device.h"
@ -20,15 +21,29 @@ namespace xe {
namespace gpu { namespace gpu {
namespace vulkan { namespace vulkan {
// Configures and caches pipelines based on render state. // Manages the virtualized EDRAM and the render target cache.
// This is responsible for properly setting all state required for a draw //
// including shaders, various blend/etc options, and input configuration. // 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 { class RenderCache {
public: public:
RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device); RenderCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);
~RenderCache(); ~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(); void EndRenderPass();
// Clears all cached content. // Clears all cached content.

View File

@ -20,9 +20,7 @@ namespace xe {
namespace gpu { namespace gpu {
namespace vulkan { 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 { class TextureCache {
public: public:
TextureCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device); TextureCache(RegisterFile* register_file, ui::vulkan::VulkanDevice* device);

View File

@ -175,6 +175,16 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
return IssueCopy(); 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<VulkanShader*>(active_vertex_shader());
auto pixel_shader = static_cast<VulkanShader*>(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. // TODO(benvanik): bigger batches.
command_buffer_pool_->BeginBatch(); command_buffer_pool_->BeginBatch();
VkCommandBuffer command_buffer = command_buffer_pool_->AcquireEntry(); VkCommandBuffer command_buffer = command_buffer_pool_->AcquireEntry();
@ -188,7 +198,8 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
// Begin the render pass. // Begin the render pass.
// This will setup our framebuffer and begin the pass in the command buffer. // 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) { if (!render_pass) {
return false; return false;
} }
@ -197,14 +208,13 @@ bool VulkanCommandProcessor::IssueDraw(PrimitiveType primitive_type,
// This encodes all render state (blend, depth, etc), our shader stages, // This encodes all render state (blend, depth, etc), our shader stages,
// and our vertex input layout. // and our vertex input layout.
if (!pipeline_cache_->ConfigurePipeline(command_buffer, render_pass, if (!pipeline_cache_->ConfigurePipeline(command_buffer, render_pass,
vertex_shader, pixel_shader,
primitive_type)) { primitive_type)) {
render_cache_->EndRenderPass(); render_cache_->EndRenderPass();
return false; return false;
} }
// Upload the constants the shaders require. // 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( auto vertex_constant_offset = buffer_cache_->UploadConstantRegisters(
vertex_shader->constant_register_map()); vertex_shader->constant_register_map());
auto pixel_constant_offset = buffer_cache_->UploadConstantRegisters( auto pixel_constant_offset = buffer_cache_->UploadConstantRegisters(

View File

@ -12,4 +12,6 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
#define FINE_GRAINED_DRAW_SCOPES 1
#endif // XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_ #endif // XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_

View File

@ -9,20 +9,47 @@
#include "xenia/gpu/vulkan/vulkan_shader.h" #include "xenia/gpu/vulkan/vulkan_shader.h"
#include "xenia/base/assert.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/ui/vulkan/vulkan_util.h"
namespace xe { namespace xe {
namespace gpu { namespace gpu {
namespace vulkan { namespace vulkan {
VulkanShader::VulkanShader(ShaderType shader_type, uint64_t data_hash, using xe::ui::vulkan::CheckResult;
const uint32_t* dword_ptr, uint32_t dword_count)
: Shader(shader_type, data_hash, dword_ptr, dword_count) {}
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<const uint32_t*>(translated_binary_.data());
auto err =
vkCreateShaderModule(device_, &shader_info, nullptr, &shader_module_);
CheckResult(err, "vkCreateShaderModule");
return true;
}
} // namespace vulkan } // namespace vulkan
} // namespace gpu } // namespace gpu

View File

@ -21,15 +21,17 @@ namespace vulkan {
class VulkanShader : public Shader { class VulkanShader : public Shader {
public: 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); const uint32_t* dword_ptr, uint32_t dword_count);
~VulkanShader() override; ~VulkanShader() override;
// Available only if the shader is_valid and has been prepared.
VkShaderModule shader_module() const { return shader_module_; } VkShaderModule shader_module() const { return shader_module_; }
bool Prepare(); bool Prepare();
private: private:
VkDevice device_ = nullptr;
VkShaderModule shader_module_ = nullptr; VkShaderModule shader_module_ = nullptr;
}; };