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.
// 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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<const uint32_t*>(translated_binary_.data());
auto err =
vkCreateShaderModule(device_, &shader_info, nullptr, &shader_module_);
CheckResult(err, "vkCreateShaderModule");
return true;
}
} // namespace vulkan
} // namespace gpu

View File

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