Skip to content

Commit 9e618c0

Browse files
video_core: Add multipler to handle special cases of texture buffer stride mismatch (shadps4-emu#1640)
* page_manager: Enable userfaultfd by default * Much faster than page faults and causes less problems * shader_recompiler: Add texel buffer multiplier * Fixes format mismatch assert when vsharp stride is multiple of format stride * shader_recompiler: Specialize UBOs on size * Some games can perform manual vertex pulling and thus bind read only buffers of varying size. We only recompile when the vsharp size is larger than size in shader, in opposite case its not needed * clang format
1 parent d05846a commit 9e618c0

File tree

8 files changed

+30
-7
lines changed

8 files changed

+30
-7
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,10 @@ target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAlloca
875875
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
876876
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
877877

878+
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
879+
target_compile_definitions(shadps4 PRIVATE ENABLE_USERFAULTFD)
880+
endif()
881+
878882
if (APPLE)
879883
option(USE_SYSTEM_VULKAN_LOADER "Enables using the system Vulkan loader instead of directly linking with MoltenVK. Useful for loading validation layers." OFF)
880884
if (USE_SYSTEM_VULKAN_LOADER)

src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,9 @@ Id EmitLoadBufferU32x4(EmitContext& ctx, IR::Inst*, u32 handle, Id address) {
326326
Id EmitLoadBufferFormatF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address) {
327327
const auto& buffer = ctx.texture_buffers[handle];
328328
const Id tex_buffer = ctx.OpLoad(buffer.image_type, buffer.id);
329-
const Id coord = ctx.OpIAdd(ctx.U32[1], address, buffer.coord_offset);
329+
const Id coord =
330+
ctx.OpIAdd(ctx.U32[1], ctx.OpShiftLeftLogical(ctx.U32[1], address, buffer.coord_shift),
331+
buffer.coord_offset);
330332
Id texel = buffer.is_storage ? ctx.OpImageRead(buffer.result_type, tex_buffer, coord)
331333
: ctx.OpImageFetch(buffer.result_type, tex_buffer, coord);
332334
if (buffer.is_integer) {
@@ -372,7 +374,9 @@ void EmitStoreBufferU32x4(EmitContext& ctx, IR::Inst* inst, u32 handle, Id addre
372374
void EmitStoreBufferFormatF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value) {
373375
const auto& buffer = ctx.texture_buffers[handle];
374376
const Id tex_buffer = ctx.OpLoad(buffer.image_type, buffer.id);
375-
const Id coord = ctx.OpIAdd(ctx.U32[1], address, buffer.coord_offset);
377+
const Id coord =
378+
ctx.OpIAdd(ctx.U32[1], ctx.OpShiftLeftLogical(ctx.U32[1], address, buffer.coord_shift),
379+
buffer.coord_offset);
376380
if (buffer.is_integer) {
377381
value = ctx.OpBitcast(buffer.result_type, value);
378382
}

src/shader_recompiler/backend/spirv/spirv_emit_context.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,8 @@ void EmitContext::DefineBufferOffsets() {
207207
push_data_block, ConstU32(half), ConstU32(comp))};
208208
const Id value{OpLoad(U32[1], ptr)};
209209
tex_buffer.coord_offset = OpBitFieldUExtract(U32[1], value, ConstU32(offset), ConstU32(6U));
210+
tex_buffer.coord_shift =
211+
OpBitFieldUExtract(U32[1], value, ConstU32(offset + 6U), ConstU32(2U));
210212
Name(tex_buffer.coord_offset, fmt::format("texbuf{}_off", binding));
211213
}
212214
}

src/shader_recompiler/backend/spirv/spirv_emit_context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ class EmitContext final : public Sirit::Module {
223223
struct TextureBufferDefinition {
224224
Id id;
225225
Id coord_offset;
226+
Id coord_shift;
226227
u32 binding;
227228
Id image_type;
228229
Id result_type;

src/shader_recompiler/info.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ struct PushData {
105105
ASSERT(offset < 256 && binding < buf_offsets.size());
106106
buf_offsets[binding] = offset;
107107
}
108+
109+
void AddTexelOffset(u32 binding, u32 multiplier, u32 texel_offset) {
110+
ASSERT(texel_offset < 64 && multiplier < 16);
111+
buf_offsets[binding] = texel_offset | ((std::bit_width(multiplier) - 1) << 6);
112+
}
108113
};
109114
static_assert(sizeof(PushData) <= 128,
110115
"PushData size is greater than minimum size guaranteed by Vulkan spec");

src/shader_recompiler/specialization.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#include "frontend/fetch_shader.h"
1010
#include "shader_recompiler/backend/bindings.h"
1111
#include "shader_recompiler/info.h"
12-
#include "shader_recompiler/ir/passes/srt.h"
1312

1413
namespace Shader {
1514

@@ -22,8 +21,12 @@ struct VsAttribSpecialization {
2221
struct BufferSpecialization {
2322
u16 stride : 14;
2423
u16 is_storage : 1;
24+
u32 size = 0;
2525

26-
auto operator<=>(const BufferSpecialization&) const = default;
26+
bool operator==(const BufferSpecialization& other) const {
27+
return stride == other.stride && is_storage == other.is_storage &&
28+
(size >= other.is_storage || is_storage);
29+
}
2730
};
2831

2932
struct TextureBufferSpecialization {
@@ -86,6 +89,9 @@ struct StageSpecialization {
8689
[](auto& spec, const auto& desc, AmdGpu::Buffer sharp) {
8790
spec.stride = sharp.GetStride();
8891
spec.is_storage = desc.IsStorage(sharp);
92+
if (!spec.is_storage) {
93+
spec.size = sharp.GetSize();
94+
}
8995
});
9096
ForEachSharp(binding, tex_buffers, info->texture_buffers,
9197
[](auto& spec, const auto& desc, AmdGpu::Buffer sharp) {

src/video_core/page_manager.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace VideoCore {
2929
constexpr size_t PAGESIZE = 4_KB;
3030
constexpr size_t PAGEBITS = 12;
3131

32-
#if ENABLE_USERFAULTFD
32+
#ifdef ENABLE_USERFAULTFD
3333
struct PageManager::Impl {
3434
Impl(Vulkan::Rasterizer* rasterizer_) : rasterizer{rasterizer_} {
3535
uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);

src/video_core/renderer_vulkan/vk_rasterizer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,13 @@ void Rasterizer::BindBuffers(const Shader::Info& stage, Shader::Backend::Binding
548548
const auto [vk_buffer, offset] = buffer_cache.ObtainBuffer(
549549
vsharp.base_address, vsharp.GetSize(), desc.is_written, true, buffer_id);
550550
const u32 fmt_stride = AmdGpu::NumBits(vsharp.GetDataFmt()) >> 3;
551-
ASSERT_MSG(fmt_stride == vsharp.GetStride(),
551+
const u32 buf_stride = vsharp.GetStride();
552+
ASSERT_MSG(buf_stride % fmt_stride == 0,
552553
"Texel buffer stride must match format stride");
553554
const u32 offset_aligned = Common::AlignDown(offset, alignment);
554555
const u32 adjust = offset - offset_aligned;
555556
ASSERT(adjust % fmt_stride == 0);
556-
push_data.AddOffset(binding.buffer, adjust / fmt_stride);
557+
push_data.AddTexelOffset(binding.buffer, buf_stride / fmt_stride, adjust / fmt_stride);
557558
buffer_view =
558559
vk_buffer->View(offset_aligned, vsharp.GetSize() + adjust, desc.is_written,
559560
vsharp.GetDataFmt(), vsharp.GetNumberFmt());

0 commit comments

Comments
 (0)