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.
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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_
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue