mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 16:25:45 +00:00
[vk, opengl] Prevent GPU draw call if CBUF binding fails (cbuf0 error handling) (#2)
Add defensive checks to cancel draw calls early if any graphics storage buffer (CBUF) fails to bind properly. - Modified BindGraphicsStorageBuffer to return false on invalid buffer ID., - ConfigureImpl (both OpenGL and Vulkan) now propagates binding failure., - Pipeline::Configure returns false if CBUF binding fails., - PrepareDraw cancels rendering if pipeline configuration fails., This avoids undefined GPU behavior, draw corruption, or crashes caused by uninitialized or invalid constant buffer (CBUF0) access, particularly in games with faulty or missing shader bindings. Eden Collaborator: <edencollaborator@eden-emu.org> Authored-by: CamilleLaVey <camillelavey@eden-emu.org> Signed-off-by: Bix <bix@bixed.xyz> Co-authored-by: Bix <114880614+Bixbr@users.noreply.github.com> Co-authored-by: crueter <crueter@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2 Co-authored-by: Ghost <> Co-committed-by: Ghost <>
This commit is contained in:
parent
1cd51d6545
commit
c47f6615d3
8 changed files with 44 additions and 21 deletions
|
@ -416,7 +416,7 @@ void BufferCache<P>::UnbindGraphicsStorageBuffers(size_t stage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
|
bool BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index,
|
||||||
u32 cbuf_offset, bool is_written) {
|
u32 cbuf_offset, bool is_written) {
|
||||||
channel_state->enabled_storage_buffers[stage] |= 1U << ssbo_index;
|
channel_state->enabled_storage_buffers[stage] |= 1U << ssbo_index;
|
||||||
channel_state->written_storage_buffers[stage] |= (is_written ? 1U : 0U) << ssbo_index;
|
channel_state->written_storage_buffers[stage] |= (is_written ? 1U : 0U) << ssbo_index;
|
||||||
|
@ -425,6 +425,7 @@ void BufferCache<P>::BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index,
|
||||||
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
const GPUVAddr ssbo_addr = cbufs.const_buffers[cbuf_index].address + cbuf_offset;
|
||||||
channel_state->storage_buffers[stage][ssbo_index] =
|
channel_state->storage_buffers[stage][ssbo_index] =
|
||||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
||||||
|
return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class P>
|
template <class P>
|
||||||
|
|
|
@ -235,7 +235,7 @@ public:
|
||||||
|
|
||||||
void UnbindGraphicsStorageBuffers(size_t stage);
|
void UnbindGraphicsStorageBuffers(size_t stage);
|
||||||
|
|
||||||
void BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
bool BindGraphicsStorageBuffer(size_t stage, size_t ssbo_index, u32 cbuf_index, u32 cbuf_offset,
|
||||||
bool is_written);
|
bool is_written);
|
||||||
|
|
||||||
void UnbindGraphicsTextureBuffers(size_t stage);
|
void UnbindGraphicsTextureBuffers(size_t stage);
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -128,7 +131,7 @@ bool Passes(const std::array<Shader::Info, 5>& stage_infos, u32 enabled_mask) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
using ConfigureFuncPtr = void (*)(GraphicsPipeline*, bool);
|
using ConfigureFuncPtr = bool (*)(GraphicsPipeline*, bool);
|
||||||
|
|
||||||
template <typename Spec, typename... Specs>
|
template <typename Spec, typename... Specs>
|
||||||
ConfigureFuncPtr FindSpec(const std::array<Shader::Info, 5>& stage_infos, u32 enabled_mask) {
|
ConfigureFuncPtr FindSpec(const std::array<Shader::Info, 5>& stage_infos, u32 enabled_mask) {
|
||||||
|
@ -275,7 +278,7 @@ GraphicsPipeline::GraphicsPipeline(const Device& device, TextureCache& texture_c
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Spec>
|
template <typename Spec>
|
||||||
void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
std::array<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
|
std::array<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
|
||||||
std::array<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
|
std::array<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
|
||||||
size_t views_index{};
|
size_t views_index{};
|
||||||
|
@ -556,6 +559,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
if (image_binding != 0) {
|
if (image_binding != 0) {
|
||||||
glBindImageTextures(0, image_binding, images.data());
|
glBindImageTextures(0, image_binding, images.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsPipeline::ConfigureTransformFeedbackImpl() const {
|
void GraphicsPipeline::ConfigureTransformFeedbackImpl() const {
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -80,8 +83,8 @@ public:
|
||||||
const std::array<const Shader::Info*, 5>& infos,
|
const std::array<const Shader::Info*, 5>& infos,
|
||||||
const GraphicsPipelineKey& key_, bool force_context_flush = false);
|
const GraphicsPipelineKey& key_, bool force_context_flush = false);
|
||||||
|
|
||||||
void Configure(bool is_indexed) {
|
bool Configure(bool is_indexed) {
|
||||||
configure_func(this, is_indexed);
|
return configure_func(this, is_indexed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureTransformFeedback() const {
|
void ConfigureTransformFeedback() const {
|
||||||
|
@ -107,7 +110,7 @@ public:
|
||||||
template <typename Spec>
|
template <typename Spec>
|
||||||
static auto MakeConfigureSpecFunc() {
|
static auto MakeConfigureSpecFunc() {
|
||||||
return [](GraphicsPipeline* pipeline, bool is_indexed) {
|
return [](GraphicsPipeline* pipeline, bool is_indexed) {
|
||||||
pipeline->ConfigureImpl<Spec>(is_indexed);
|
return pipeline->ConfigureImpl<Spec>(is_indexed);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +121,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Spec>
|
template <typename Spec>
|
||||||
void ConfigureImpl(bool is_indexed);
|
bool ConfigureImpl(bool is_indexed);
|
||||||
|
|
||||||
void ConfigureTransformFeedbackImpl() const;
|
void ConfigureTransformFeedbackImpl() const;
|
||||||
|
|
||||||
|
@ -134,7 +137,7 @@ private:
|
||||||
StateTracker& state_tracker;
|
StateTracker& state_tracker;
|
||||||
const GraphicsPipelineKey key;
|
const GraphicsPipelineKey key;
|
||||||
|
|
||||||
void (*configure_func)(GraphicsPipeline*, bool){};
|
bool (*configure_func)(GraphicsPipeline*, bool){};
|
||||||
|
|
||||||
std::array<OGLProgram, 5> source_programs;
|
std::array<OGLProgram, 5> source_programs;
|
||||||
std::array<OGLAssemblyProgram, 5> assembly_programs;
|
std::array<OGLAssemblyProgram, 5> assembly_programs;
|
||||||
|
|
|
@ -250,7 +250,8 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||||
program_manager.LocalMemoryWarmup();
|
program_manager.LocalMemoryWarmup();
|
||||||
}
|
}
|
||||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||||
pipeline->Configure(is_indexed);
|
if (!pipeline->Configure(is_indexed))
|
||||||
|
return;
|
||||||
|
|
||||||
SyncState();
|
SyncState();
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -175,7 +178,7 @@ bool Passes(const std::array<vk::ShaderModule, NUM_STAGES>& modules,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
using ConfigureFuncPtr = void (*)(GraphicsPipeline*, bool);
|
using ConfigureFuncPtr = bool (*)(GraphicsPipeline*, bool);
|
||||||
|
|
||||||
template <typename Spec, typename... Specs>
|
template <typename Spec, typename... Specs>
|
||||||
ConfigureFuncPtr FindSpec(const std::array<vk::ShaderModule, NUM_STAGES>& modules,
|
ConfigureFuncPtr FindSpec(const std::array<vk::ShaderModule, NUM_STAGES>& modules,
|
||||||
|
@ -302,7 +305,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Spec>
|
template <typename Spec>
|
||||||
void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views;
|
std::array<VideoCommon::ImageViewInOut, MAX_IMAGE_ELEMENTS> views;
|
||||||
std::array<VideoCommon::SamplerId, MAX_IMAGE_ELEMENTS> samplers;
|
std::array<VideoCommon::SamplerId, MAX_IMAGE_ELEMENTS> samplers;
|
||||||
size_t sampler_index{};
|
size_t sampler_index{};
|
||||||
|
@ -321,8 +324,9 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
size_t ssbo_index{};
|
size_t ssbo_index{};
|
||||||
for (const auto& desc : info.storage_buffers_descriptors) {
|
for (const auto& desc : info.storage_buffers_descriptors) {
|
||||||
ASSERT(desc.count == 1);
|
ASSERT(desc.count == 1);
|
||||||
buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index,
|
if (!buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index,
|
||||||
desc.cbuf_offset, desc.is_written);
|
desc.cbuf_offset, desc.is_written))
|
||||||
|
return false;
|
||||||
++ssbo_index;
|
++ssbo_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,6 +386,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
add_image(desc, desc.is_written);
|
add_image(desc, desc.is_written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}};
|
}};
|
||||||
if constexpr (Spec::enabled_stages[0]) {
|
if constexpr (Spec::enabled_stages[0]) {
|
||||||
config_stage(0);
|
config_stage(0);
|
||||||
|
@ -396,7 +402,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
config_stage(3);
|
config_stage(3);
|
||||||
}
|
}
|
||||||
if constexpr (Spec::enabled_stages[4]) {
|
if constexpr (Spec::enabled_stages[4]) {
|
||||||
config_stage(4);
|
if (!config_stage(4))
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), view_index));
|
texture_cache.FillGraphicsImageViews<Spec::has_images>(std::span(views.data(), view_index));
|
||||||
|
|
||||||
|
@ -490,6 +497,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||||
texture_cache.UpdateRenderTargets(false);
|
texture_cache.UpdateRenderTargets(false);
|
||||||
texture_cache.CheckFeedbackLoop(views);
|
texture_cache.CheckFeedbackLoop(views);
|
||||||
ConfigureDraw(rescaling, render_area);
|
ConfigureDraw(rescaling, render_area);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
@ -86,8 +89,8 @@ public:
|
||||||
|
|
||||||
void AddTransition(GraphicsPipeline* transition);
|
void AddTransition(GraphicsPipeline* transition);
|
||||||
|
|
||||||
void Configure(bool is_indexed) {
|
bool Configure(bool is_indexed) {
|
||||||
configure_func(this, is_indexed);
|
return configure_func(this, is_indexed);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept {
|
[[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept {
|
||||||
|
@ -105,7 +108,7 @@ public:
|
||||||
|
|
||||||
template <typename Spec>
|
template <typename Spec>
|
||||||
static auto MakeConfigureSpecFunc() {
|
static auto MakeConfigureSpecFunc() {
|
||||||
return [](GraphicsPipeline* pl, bool is_indexed) { pl->ConfigureImpl<Spec>(is_indexed); };
|
return [](GraphicsPipeline* pl, bool is_indexed) { return pl->ConfigureImpl<Spec>(is_indexed); };
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) {
|
void SetEngine(Tegra::Engines::Maxwell3D* maxwell3d_, Tegra::MemoryManager* gpu_memory_) {
|
||||||
|
@ -115,7 +118,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Spec>
|
template <typename Spec>
|
||||||
void ConfigureImpl(bool is_indexed);
|
bool ConfigureImpl(bool is_indexed);
|
||||||
|
|
||||||
void ConfigureDraw(const RescalingPushConstant& rescaling,
|
void ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||||
const RenderAreaPushConstant& render_are);
|
const RenderAreaPushConstant& render_are);
|
||||||
|
@ -134,7 +137,7 @@ private:
|
||||||
Scheduler& scheduler;
|
Scheduler& scheduler;
|
||||||
GuestDescriptorQueue& guest_descriptor_queue;
|
GuestDescriptorQueue& guest_descriptor_queue;
|
||||||
|
|
||||||
void (*configure_func)(GraphicsPipeline*, bool){};
|
bool (*configure_func)(GraphicsPipeline*, bool){};
|
||||||
|
|
||||||
std::vector<GraphicsPipelineCacheKey> transition_keys;
|
std::vector<GraphicsPipelineCacheKey> transition_keys;
|
||||||
std::vector<GraphicsPipeline*> transitions;
|
std::vector<GraphicsPipeline*> transitions;
|
||||||
|
|
|
@ -226,7 +226,8 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||||
// update engine as channel may be different.
|
// update engine as channel may be different.
|
||||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||||
pipeline->Configure(is_indexed);
|
if (!pipeline->Configure(is_indexed))
|
||||||
|
return;
|
||||||
|
|
||||||
UpdateDynamicStates();
|
UpdateDynamicStates();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue