rasterizer: Use separate buffers for vs/fs uniforms
Vulkan validation layers complain about WaR hazards since the VS range overlaps with the FS range when the buffer is invalidated. To solve this, split them into separate buffers
This commit is contained in:
@ -182,7 +182,8 @@ Rasterizer::Rasterizer(Frontend::EmuWindow& emu_window, std::unique_ptr<BackendB
|
|||||||
// Create rasterizer buffers
|
// Create rasterizer buffers
|
||||||
vertex_buffer = backend->CreateBuffer(VERTEX_BUFFER_INFO);
|
vertex_buffer = backend->CreateBuffer(VERTEX_BUFFER_INFO);
|
||||||
index_buffer = backend->CreateBuffer(INDEX_BUFFER_INFO);
|
index_buffer = backend->CreateBuffer(INDEX_BUFFER_INFO);
|
||||||
uniform_buffer = backend->CreateBuffer(UNIFORM_BUFFER_INFO);
|
uniform_buffer_vs = backend->CreateBuffer(UNIFORM_BUFFER_INFO);
|
||||||
|
uniform_buffer_fs = backend->CreateBuffer(UNIFORM_BUFFER_INFO);
|
||||||
texel_buffer_lut = backend->CreateBuffer(TEXEL_BUFFER_INFO);
|
texel_buffer_lut = backend->CreateBuffer(TEXEL_BUFFER_INFO);
|
||||||
texel_buffer_lut_lf = backend->CreateBuffer(TEXEL_BUFFER_LF_INFO);
|
texel_buffer_lut_lf = backend->CreateBuffer(TEXEL_BUFFER_LF_INFO);
|
||||||
|
|
||||||
@ -806,7 +807,7 @@ bool Rasterizer::Draw(bool accelerate, bool is_indexed) {
|
|||||||
raster_pipeline->BindSampler(SAMPLER_GROUP, texture_index, iter->second);
|
raster_pipeline->BindSampler(SAMPLER_GROUP, texture_index, iter->second);
|
||||||
} else {
|
} else {
|
||||||
SamplerHandle texture_sampler = backend->CreateSampler(key);
|
SamplerHandle texture_sampler = backend->CreateSampler(key);
|
||||||
auto result = sampler_cache.emplace(key, texture_sampler);
|
sampler_cache.emplace(key, texture_sampler);
|
||||||
raster_pipeline->BindSampler(SAMPLER_GROUP, texture_index, texture_sampler);
|
raster_pipeline->BindSampler(SAMPLER_GROUP, texture_index, texture_sampler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2056,37 +2057,32 @@ void Rasterizer::UploadUniforms(PipelineHandle pipeline, bool accelerate_draw) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t uniform_size = uniform_size_aligned_vs + uniform_size_aligned_fs;
|
|
||||||
std::size_t used_bytes = 0;
|
|
||||||
|
|
||||||
auto uniforms = uniform_buffer->Map(uniform_size, uniform_buffer_alignment);
|
|
||||||
const bool invalidate = uniform_buffer->IsInvalid();
|
|
||||||
const u32 offset = uniform_buffer->GetCurrentOffset();
|
|
||||||
|
|
||||||
// Re-bind uniform buffer with the new range
|
|
||||||
pipeline->BindBuffer(UTILITY_GROUP, 0, uniform_buffer, offset + used_bytes, sizeof(VSUniformData));
|
|
||||||
|
|
||||||
if (sync_vs) {
|
if (sync_vs) {
|
||||||
VSUniformData vs_uniforms;
|
VSUniformData vs_uniforms;
|
||||||
vs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.vs, Pica::g_state.vs);
|
vs_uniforms.uniforms.SetFromRegs(Pica::g_state.regs.vs, Pica::g_state.vs);
|
||||||
std::memcpy(uniforms.data() + used_bytes, &vs_uniforms, sizeof(vs_uniforms));
|
|
||||||
|
|
||||||
used_bytes += uniform_size_aligned_vs;
|
auto uniforms = uniform_buffer_vs->Map(uniform_size_aligned_vs, uniform_buffer_alignment);
|
||||||
|
uniform_block_data.current_vs_offset = uniform_buffer_vs->GetCurrentOffset();
|
||||||
|
|
||||||
|
std::memcpy(uniforms.data(), &vs_uniforms, sizeof(vs_uniforms));
|
||||||
|
uniform_buffer_vs->Commit(uniform_size_aligned_vs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Re-bind uniform buffer with the new range
|
if (sync_fs) {
|
||||||
pipeline->BindBuffer(UTILITY_GROUP, 1, uniform_buffer, offset + used_bytes, sizeof(UniformData));
|
auto uniforms = uniform_buffer_fs->Map(uniform_size_aligned_fs, uniform_buffer_alignment);
|
||||||
|
uniform_block_data.current_fs_offset = uniform_buffer_fs->GetCurrentOffset();
|
||||||
|
|
||||||
if (sync_fs || invalidate) {
|
std::memcpy(uniforms.data(), &uniform_block_data.data, sizeof(UniformData));
|
||||||
std::memcpy(uniforms.data() + used_bytes, &uniform_block_data.data, sizeof(UniformData));
|
|
||||||
|
|
||||||
uniform_block_data.dirty = false;
|
uniform_block_data.dirty = false;
|
||||||
used_bytes += uniform_size_aligned_fs;
|
uniform_buffer_fs->Commit(uniform_size_aligned_fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (used_bytes > 0) {
|
// Bind updated ranges
|
||||||
uniform_buffer->Commit(used_bytes);
|
pipeline->BindBuffer(UTILITY_GROUP, 0, uniform_buffer_vs, uniform_block_data.current_vs_offset,
|
||||||
}
|
sizeof(VSUniformData));
|
||||||
|
pipeline->BindBuffer(UTILITY_GROUP, 1, uniform_buffer_fs, uniform_block_data.current_fs_offset,
|
||||||
|
sizeof(UniformData));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace VideoCore
|
} // namespace VideoCore
|
||||||
|
@ -206,6 +206,8 @@ private:
|
|||||||
bool proctex_lut_dirty = true;
|
bool proctex_lut_dirty = true;
|
||||||
bool proctex_diff_lut_dirty = true;
|
bool proctex_diff_lut_dirty = true;
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
|
u32 current_vs_offset = 0;
|
||||||
|
u32 current_fs_offset = 0;
|
||||||
} uniform_block_data{};
|
} uniform_block_data{};
|
||||||
|
|
||||||
// Pipeline information structure used to identify a rasterizer pipeline
|
// Pipeline information structure used to identify a rasterizer pipeline
|
||||||
@ -223,7 +225,8 @@ private:
|
|||||||
std::size_t uniform_size_aligned_fs = 0;
|
std::size_t uniform_size_aligned_fs = 0;
|
||||||
|
|
||||||
// Rasterizer used buffers (vertex, index, uniform, lut)
|
// Rasterizer used buffers (vertex, index, uniform, lut)
|
||||||
BufferHandle vertex_buffer, index_buffer, uniform_buffer;
|
BufferHandle vertex_buffer, index_buffer;
|
||||||
|
BufferHandle uniform_buffer_vs, uniform_buffer_fs;
|
||||||
BufferHandle texel_buffer_lut_lf, texel_buffer_lut;
|
BufferHandle texel_buffer_lut_lf, texel_buffer_lut;
|
||||||
|
|
||||||
// Pica lighting data
|
// Pica lighting data
|
||||||
@ -239,9 +242,6 @@ private:
|
|||||||
SamplerHandle texture_cube_sampler;
|
SamplerHandle texture_cube_sampler;
|
||||||
std::array<SamplerInfo, 3> texture_samplers;
|
std::array<SamplerInfo, 3> texture_samplers;
|
||||||
std::unordered_map<SamplerInfo, SamplerHandle> sampler_cache;
|
std::unordered_map<SamplerInfo, SamplerHandle> sampler_cache;
|
||||||
|
|
||||||
// TODO: Remove this
|
|
||||||
bool allow_shadow = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCore
|
} // namespace VideoCore
|
||||||
|
@ -106,6 +106,11 @@ bool Backend::BeginPresent() {
|
|||||||
void Backend::EndPresent() {
|
void Backend::EndPresent() {
|
||||||
// Transition swapchain image to present layout
|
// Transition swapchain image to present layout
|
||||||
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
|
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
|
||||||
|
/*if (renderpass_active) {
|
||||||
|
command_buffer.endRenderPass();
|
||||||
|
renderpass_active = false;
|
||||||
|
}*/
|
||||||
|
|
||||||
swapchain.GetCurrentImage()->Transition(command_buffer, vk::ImageLayout::ePresentSrcKHR);
|
swapchain.GetCurrentImage()->Transition(command_buffer, vk::ImageLayout::ePresentSrcKHR);
|
||||||
|
|
||||||
// Submit and present
|
// Submit and present
|
||||||
@ -291,7 +296,12 @@ void Backend::BindDescriptorSets(PipelineHandle handle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Backend::BeginRenderpass(FramebufferHandle draw_framebuffer) {
|
void Backend::BeginRenderpass(FramebufferHandle draw_framebuffer) {
|
||||||
|
/*if (draw_framebuffer == current_framebuffer && renderpass_active) {
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
Framebuffer* framebuffer = static_cast<Framebuffer*>(draw_framebuffer.Get());
|
Framebuffer* framebuffer = static_cast<Framebuffer*>(draw_framebuffer.Get());
|
||||||
|
//current_framebuffer = draw_framebuffer;
|
||||||
|
|
||||||
u32 clear_value_count = 0;
|
u32 clear_value_count = 0;
|
||||||
std::array<vk::ClearValue, 2> clear_values{};
|
std::array<vk::ClearValue, 2> clear_values{};
|
||||||
@ -323,7 +333,12 @@ void Backend::BeginRenderpass(FramebufferHandle draw_framebuffer) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
|
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
|
||||||
|
/*if (renderpass_active) {
|
||||||
|
command_buffer.endRenderPass();
|
||||||
|
}
|
||||||
|
*/
|
||||||
command_buffer.beginRenderPass(renderpass_begin, vk::SubpassContents::eInline);
|
command_buffer.beginRenderPass(renderpass_begin, vk::SubpassContents::eInline);
|
||||||
|
//renderpass_active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Backend::OnCommandSwitch(u32 new_slot) {
|
void Backend::OnCommandSwitch(u32 new_slot) {
|
||||||
|
@ -72,11 +72,10 @@ private:
|
|||||||
Swapchain swapchain;
|
Swapchain swapchain;
|
||||||
vk::PipelineCache pipeline_cache;
|
vk::PipelineCache pipeline_cache;
|
||||||
|
|
||||||
// A cache of pipeline owners
|
|
||||||
std::unordered_map<u64, std::unique_ptr<PipelineOwner>, Common::IdentityHash> pipeline_owners;
|
std::unordered_map<u64, std::unique_ptr<PipelineOwner>, Common::IdentityHash> pipeline_owners;
|
||||||
|
|
||||||
// Descriptor pools
|
|
||||||
std::array<vk::DescriptorPool, SCHEDULER_COMMAND_COUNT> descriptor_pools;
|
std::array<vk::DescriptorPool, SCHEDULER_COMMAND_COUNT> descriptor_pools;
|
||||||
|
//FramebufferHandle current_framebuffer;
|
||||||
|
//bool renderpass_active = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
@ -34,7 +34,7 @@ struct LightSrc {
|
|||||||
float dist_atten_scale;
|
float dist_atten_scale;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout (set = 0, binding = 0) uniform shader_data {
|
layout (std140, set = 0, binding = 1) uniform shader_data {
|
||||||
int framebuffer_scale;
|
int framebuffer_scale;
|
||||||
int alphatest_ref;
|
int alphatest_ref;
|
||||||
float depth_scale;
|
float depth_scale;
|
||||||
|
Reference in New Issue
Block a user