mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 11:45:47 +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>
|
||||
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) {
|
||||
channel_state->enabled_storage_buffers[stage] |= 1U << 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;
|
||||
channel_state->storage_buffers[stage][ssbo_index] =
|
||||
StorageBufferBinding(ssbo_addr, cbuf_index, is_written);
|
||||
return (channel_state->storage_buffers[stage][ssbo_index].buffer_id != NULL_BUFFER_ID);
|
||||
}
|
||||
|
||||
template <class P>
|
||||
|
|
|
@ -235,7 +235,7 @@ public:
|
|||
|
||||
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);
|
||||
|
||||
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-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;
|
||||
}
|
||||
|
||||
using ConfigureFuncPtr = void (*)(GraphicsPipeline*, bool);
|
||||
using ConfigureFuncPtr = bool (*)(GraphicsPipeline*, bool);
|
||||
|
||||
template <typename Spec, typename... Specs>
|
||||
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>
|
||||
void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
std::array<VideoCommon::ImageViewInOut, MAX_TEXTURES + MAX_IMAGES> views;
|
||||
std::array<VideoCommon::SamplerId, MAX_TEXTURES> samplers;
|
||||
size_t views_index{};
|
||||
|
@ -556,6 +559,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||
if (image_binding != 0) {
|
||||
glBindImageTextures(0, image_binding, images.data());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -80,8 +83,8 @@ public:
|
|||
const std::array<const Shader::Info*, 5>& infos,
|
||||
const GraphicsPipelineKey& key_, bool force_context_flush = false);
|
||||
|
||||
void Configure(bool is_indexed) {
|
||||
configure_func(this, is_indexed);
|
||||
bool Configure(bool is_indexed) {
|
||||
return configure_func(this, is_indexed);
|
||||
}
|
||||
|
||||
void ConfigureTransformFeedback() const {
|
||||
|
@ -107,7 +110,7 @@ public:
|
|||
template <typename Spec>
|
||||
static auto MakeConfigureSpecFunc() {
|
||||
return [](GraphicsPipeline* pipeline, bool is_indexed) {
|
||||
pipeline->ConfigureImpl<Spec>(is_indexed);
|
||||
return pipeline->ConfigureImpl<Spec>(is_indexed);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -118,7 +121,7 @@ public:
|
|||
|
||||
private:
|
||||
template <typename Spec>
|
||||
void ConfigureImpl(bool is_indexed);
|
||||
bool ConfigureImpl(bool is_indexed);
|
||||
|
||||
void ConfigureTransformFeedbackImpl() const;
|
||||
|
||||
|
@ -134,7 +137,7 @@ private:
|
|||
StateTracker& state_tracker;
|
||||
const GraphicsPipelineKey key;
|
||||
|
||||
void (*configure_func)(GraphicsPipeline*, bool){};
|
||||
bool (*configure_func)(GraphicsPipeline*, bool){};
|
||||
|
||||
std::array<OGLProgram, 5> source_programs;
|
||||
std::array<OGLAssemblyProgram, 5> assembly_programs;
|
||||
|
|
|
@ -250,7 +250,8 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
|||
program_manager.LocalMemoryWarmup();
|
||||
}
|
||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||
pipeline->Configure(is_indexed);
|
||||
if (!pipeline->Configure(is_indexed))
|
||||
return;
|
||||
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -175,7 +178,7 @@ bool Passes(const std::array<vk::ShaderModule, NUM_STAGES>& modules,
|
|||
return true;
|
||||
}
|
||||
|
||||
using ConfigureFuncPtr = void (*)(GraphicsPipeline*, bool);
|
||||
using ConfigureFuncPtr = bool (*)(GraphicsPipeline*, bool);
|
||||
|
||||
template <typename Spec, typename... Specs>
|
||||
ConfigureFuncPtr FindSpec(const std::array<vk::ShaderModule, NUM_STAGES>& modules,
|
||||
|
@ -302,7 +305,7 @@ void GraphicsPipeline::AddTransition(GraphicsPipeline* transition) {
|
|||
}
|
||||
|
||||
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::SamplerId, MAX_IMAGE_ELEMENTS> samplers;
|
||||
size_t sampler_index{};
|
||||
|
@ -321,8 +324,9 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||
size_t ssbo_index{};
|
||||
for (const auto& desc : info.storage_buffers_descriptors) {
|
||||
ASSERT(desc.count == 1);
|
||||
buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index,
|
||||
desc.cbuf_offset, desc.is_written);
|
||||
if (!buffer_cache.BindGraphicsStorageBuffer(stage, ssbo_index, desc.cbuf_index,
|
||||
desc.cbuf_offset, desc.is_written))
|
||||
return false;
|
||||
++ssbo_index;
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +386,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||
add_image(desc, desc.is_written);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}};
|
||||
if constexpr (Spec::enabled_stages[0]) {
|
||||
config_stage(0);
|
||||
|
@ -396,7 +402,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||
config_stage(3);
|
||||
}
|
||||
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));
|
||||
|
||||
|
@ -490,6 +497,8 @@ void GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
|||
texture_cache.UpdateRenderTargets(false);
|
||||
texture_cache.CheckFeedbackLoop(views);
|
||||
ConfigureDraw(rescaling, render_area);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
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-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -86,8 +89,8 @@ public:
|
|||
|
||||
void AddTransition(GraphicsPipeline* transition);
|
||||
|
||||
void Configure(bool is_indexed) {
|
||||
configure_func(this, is_indexed);
|
||||
bool Configure(bool is_indexed) {
|
||||
return configure_func(this, is_indexed);
|
||||
}
|
||||
|
||||
[[nodiscard]] GraphicsPipeline* Next(const GraphicsPipelineCacheKey& current_key) noexcept {
|
||||
|
@ -105,7 +108,7 @@ public:
|
|||
|
||||
template <typename Spec>
|
||||
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_) {
|
||||
|
@ -115,7 +118,7 @@ public:
|
|||
|
||||
private:
|
||||
template <typename Spec>
|
||||
void ConfigureImpl(bool is_indexed);
|
||||
bool ConfigureImpl(bool is_indexed);
|
||||
|
||||
void ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||
const RenderAreaPushConstant& render_are);
|
||||
|
@ -134,7 +137,7 @@ private:
|
|||
Scheduler& scheduler;
|
||||
GuestDescriptorQueue& guest_descriptor_queue;
|
||||
|
||||
void (*configure_func)(GraphicsPipeline*, bool){};
|
||||
bool (*configure_func)(GraphicsPipeline*, bool){};
|
||||
|
||||
std::vector<GraphicsPipelineCacheKey> transition_keys;
|
||||
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};
|
||||
// update engine as channel may be different.
|
||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||
pipeline->Configure(is_indexed);
|
||||
if (!pipeline->Configure(is_indexed))
|
||||
return;
|
||||
|
||||
UpdateDynamicStates();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue