diff options
| author | Duck912 <350528965+Duck912@users.noreply.github.com> | 2026-11-01 21:42:19 -0500 |
|---|---|---|
| committer | Duck912 <350528965+Duck912@users.noreply.github.com> | 2026-11-01 21:54:48 -0500 |
| commit | 808feaf3bf34b3c108ff30baae1d2261f216f4f3 (patch) | |
| tree | 41d9d0eb9e746098797d0c5a55fd1841c333b681 /src/video_core/buffer_cache/buffer_cache.h | |
| parent | 9acc324228b7028f947e053a08c18543f631e5ce (diff) | |
video_core: keep root tables and bind table 0 as constant bank 17
The 3D methods 0x504/0x508 write eight 256-byte root tables, which
shaders read as constant banks 24-31; NVN2 keeps push constants in table
0 (bank 17 after the Ampere lowering). Fire Emblem: Fortune's Weave
keeps its material constants there and never binds bank 17, and the
blit constants pass replaced those reads with render-target sizes,
flooding its 3D scenes red.
Maxwell3D now keeps the tables, the buffer cache streams table 0 as bank
17 when the game has not bound one, and the blit constants pass leaves
shaders that read bank 17 outside its parameter block alone.
Assisted-by: Claude Opus 5.5 (debugging, implementation and drafting)
Signed-off-by: Duck912 <350528965+Duck912@users.noreply.github.com>
Diffstat (limited to 'src/video_core/buffer_cache/buffer_cache.h')
| -rw-r--r-- | src/video_core/buffer_cache/buffer_cache.h | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index e90af3214d..2fc74cb6c8 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h @@ -994,6 +994,26 @@ void BufferCache<P>::BindHostGraphicsUniformBuffers(size_t stage) { template <class P> void BufferCache<P>::BindHostGraphicsUniformBuffer(size_t stage, u32 index, u32 binding_index, bool needs_bind) { ++channel_state->uniform_cache_shots[0]; + // Bank 24 (root table 0, NVN2's push constants) is read from bank 17, which such games do not + // bind: stream the table's current words as that buffer. + if (index == 17 && maxwell3d->root_tables.loaded && channel_state->uniform_buffers[stage][index].size == 0) { + const auto& words = maxwell3d->root_tables.tables[0]; + const u32 size = (*channel_state->uniform_buffer_sizes)[stage][index]; + const u32 copied = (std::min)(size, static_cast<u32>(sizeof(words))); + if constexpr (IS_OPENGL) { + std::array<u8, sizeof(words)> data{}; + std::memcpy(data.data(), words.data(), copied); + runtime.BindFastUniformBuffer(stage, binding_index, copied); + runtime.PushFastUniformBuffer(stage, binding_index, std::span<const u8>(data.data(), copied)); + } else { + const std::span<u8> span = runtime.BindMappedUniformBuffer(stage, binding_index, size); + std::memset(span.data(), 0, span.size()); + std::memcpy(span.data(), words.data(), copied); + } + channel_state->fast_bound_uniform_buffers[stage] |= 1u << binding_index; + channel_state->uniform_buffer_binding_sizes[stage][binding_index] = size; + return; + } const Binding& binding = channel_state->uniform_buffers[stage][index]; const DAddr device_addr = binding.device_addr; const u32 size = (std::min)(binding.size, (*channel_state->uniform_buffer_sizes)[stage][index]); |
