Shader modules and plumbing.
This commit is contained in:
parent
e14b2fe766
commit
52a6f795f7
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -12,4 +12,6 @@
|
|||
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#define FINE_GRAINED_DRAW_SCOPES 1
|
||||
|
||||
#endif // XENIA_GPU_VULKAN_VULKAN_GPU_FLAGS_H_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue