diff --git a/Utilities/Thread.cpp b/Utilities/Thread.cpp index 3c04019ddf..9f7eb958bf 100644 --- a/Utilities/Thread.cpp +++ b/Utilities/Thread.cpp @@ -765,6 +765,14 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz return d_size; } +/** + * Callback that can be customised by GSRender backends to track memory access. + * Backends can protect memory pages and get this callback called when an access + * violation is met. + * Should return true if the backend handles the access violation. + */ +std::function gfxHandler = [](u32) { return false; }; + bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) { auto code = (const u8*)RIP(context); @@ -774,6 +782,9 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context) size_t d_size; size_t i_size; + if (gfxHandler(addr)) + return true; + // decode single x64 instruction that causes memory access decode_x64_reg_op(code, op, reg, d_size, i_size); diff --git a/rpcs3/Emu/Memory/vm.cpp b/rpcs3/Emu/Memory/vm.cpp index 623f1489fb..ef10b43fe6 100644 --- a/rpcs3/Emu/Memory/vm.cpp +++ b/rpcs3/Emu/Memory/vm.cpp @@ -425,10 +425,10 @@ namespace vm DWORD old; auto protection = f2 & page_writable ? PAGE_READWRITE : (f2 & page_readable ? PAGE_READONLY : PAGE_NOACCESS); - if (!VirtualProtect(real_addr, size, protection, &old)) + if (!VirtualProtect(real_addr, 4096, protection, &old)) #else auto protection = f2 & page_writable ? PROT_WRITE | PROT_READ : (f2 & page_readable ? PROT_READ : PROT_NONE); - if (mprotect(real_addr, size, protection)) + if (mprotect(real_addr, 4096, protection)) #endif { throw fmt::format("vm::page_protect(addr=0x%x, size=0x%x, flags_test=0x%x, flags_set=0x%x, flags_clear=0x%x) failed (API)", addr, size, flags_test, flags_set, flags_clear); diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.cpp b/rpcs3/Emu/RSX/GL/GLGSRender.cpp index fc37fee9b8..08adde2fb3 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.cpp +++ b/rpcs3/Emu/RSX/GL/GLGSRender.cpp @@ -1599,7 +1599,7 @@ void GLGSRender::InitDrawBuffers() } } -void GLGSRender::ExecCMD(u32 cmd) +void GLGSRender::Clear(u32 cmd) { assert(cmd == NV4097_CLEAR_SURFACE); @@ -1653,7 +1653,7 @@ void GLGSRender::ExecCMD(u32 cmd) WriteBuffers(); } -void GLGSRender::ExecCMD() +void GLGSRender::Draw() { //return; if (!LoadProgram()) @@ -1966,9 +1966,9 @@ void GLGSRender::ExecCMD() m_vao.Bind(); if (m_indexed_array.m_count) - { LoadVertexData(m_indexed_array.index_min, m_indexed_array.index_max - m_indexed_array.index_min + 1); - } + else + LoadVertexData(m_draw_array_first, m_draw_array_count); if (m_indexed_array.m_count || m_draw_array_count) { @@ -2143,6 +2143,21 @@ void GLGSRender::Flip() } +void GLGSRender::semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) +{ + vm::write32(m_label_addr + offset, value); +} + +void GLGSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value) +{ + vm::write32(m_label_addr + offset, value); +} + +void GLGSRender::semaphorePFIFOAcquire(u32 offset, u32 value) +{ + +} + u32 LinearToSwizzleAddress(u32 x, u32 y, u32 z, u32 log2_width, u32 log2_height, u32 log2_depth) { u32 offset = 0; diff --git a/rpcs3/Emu/RSX/GL/GLGSRender.h b/rpcs3/Emu/RSX/GL/GLGSRender.h index 495f940172..f1ea9cb83f 100644 --- a/rpcs3/Emu/RSX/GL/GLGSRender.h +++ b/rpcs3/Emu/RSX/GL/GLGSRender.h @@ -194,7 +194,11 @@ protected: virtual void OnInitThread(); virtual void OnExitThread(); virtual void OnReset(); - virtual void ExecCMD(u32 cmd); - virtual void ExecCMD(); + virtual void Clear(u32 cmd) override; + virtual void Draw() override; virtual void Flip(); + + virtual void semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) override; + virtual void semaphorePGRAPHBackendRelease(u32 offset, u32 value) override; + virtual void semaphorePFIFOAcquire(u32 offset, u32 value) override; }; diff --git a/rpcs3/Emu/RSX/Null/NullGSRender.h b/rpcs3/Emu/RSX/Null/NullGSRender.h index 33875cbabe..a68e70a44e 100644 --- a/rpcs3/Emu/RSX/Null/NullGSRender.h +++ b/rpcs3/Emu/RSX/Null/NullGSRender.h @@ -31,11 +31,11 @@ private: { } - virtual void ExecCMD(u32 cmd) + virtual void Clear(u32 cmd) override { } - virtual void ExecCMD() + virtual void Draw() override { } @@ -46,4 +46,16 @@ private: virtual void Close() { } + + virtual void semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) override + { + } + + virtual void semaphorePGRAPHBackendRelease(u32 offset, u32 value) override + { + } + + virtual void semaphorePFIFOAcquire(u32 offset, u32 value) override + { + } }; \ No newline at end of file diff --git a/rpcs3/Emu/RSX/RSXThread.cpp b/rpcs3/Emu/RSX/RSXThread.cpp index f204dfbd9c..e50f2ad5f2 100644 --- a/rpcs3/Emu/RSX/RSXThread.cpp +++ b/rpcs3/Emu/RSX/RSXThread.cpp @@ -201,43 +201,40 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const } case NV4097_SET_SEMAPHORE_OFFSET: + { + m_PGRAPH_semaphore_offset = ARGS(0); + break; + } + case NV406E_SEMAPHORE_OFFSET: { - m_set_semaphore_offset = true; - m_semaphore_offset = ARGS(0); + m_PFIFO_semaphore_offset = ARGS(0); break; } case NV406E_SEMAPHORE_ACQUIRE: { - if (ARGS(0)) - { - LOG_WARNING(RSX, "TODO: NV406E_SEMAPHORE_ACQUIRE: 0x%x", ARGS(0)); - } + semaphorePFIFOAcquire(m_PFIFO_semaphore_offset, ARGS(0)); break; } case NV406E_SEMAPHORE_RELEASE: + { + m_PFIFO_semaphore_release_value = ARGS(0); + break; + } + case NV4097_TEXTURE_READ_SEMAPHORE_RELEASE: { - if (m_set_semaphore_offset) - { - m_set_semaphore_offset = false; - vm::write32(m_label_addr + m_semaphore_offset, ARGS(0)); - } + semaphorePGRAPHTextureReadRelease(m_PGRAPH_semaphore_offset, ARGS(0)); break; } case NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE: { - if (m_set_semaphore_offset) - { - m_set_semaphore_offset = false; - u32 value = ARGS(0); - value = (value & 0xff00ff00) | ((value & 0xff) << 16) | ((value >> 16) & 0xff); - - vm::write32(m_label_addr + m_semaphore_offset, value); - } + u32 value = ARGS(0); + value = (value & 0xff00ff00) | ((value & 0xff) << 16) | ((value >> 16) & 0xff); + semaphorePGRAPHBackendRelease(m_PGRAPH_semaphore_offset, value); break; } @@ -850,7 +847,7 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const if (a0 & 0x80) m_clear_surface_color_a = m_clear_color_a; m_clear_surface_mask = a0; - ExecCMD(NV4097_CLEAR_SURFACE); + Clear(NV4097_CLEAR_SURFACE); break; } @@ -910,8 +907,6 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const //LOG_WARNING(RSX, "NV4097_DRAW_ARRAYS: %d - %d", first, _count); - LoadVertexData(first, _count); - if (first < m_draw_array_first) { m_draw_array_first = first; @@ -942,10 +937,10 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const switch (m_indexed_array.m_type) { - case 0: + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: m_indexed_array.m_data.resize(pos + 4 * _count); break; - case 1: + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: m_indexed_array.m_data.resize(pos + 2 * _count); break; } @@ -955,12 +950,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const u32 index; switch(m_indexed_array.m_type) { - case 0: + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_32: index = vm::read32(m_indexed_array.m_addr + i * 4); *(u32*)&m_indexed_array.m_data[i * 4] = index; break; - case 1: + case CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16: index = vm::read16(m_indexed_array.m_addr + i * 2); *(u16*)&m_indexed_array.m_data[i * 2] = index; break; @@ -1177,6 +1172,12 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, const u32 args_addr, const break; } + case NV4097_SET_NO_PARANOID_TEXTURE_FETCHES: + { + // Nothing to do here + break; + } + case NV4097_INVALIDATE_VERTEX_CACHE_FILE: { // Nothing to do here @@ -2415,7 +2416,7 @@ void RSXThread::Begin(u32 draw_mode) void RSXThread::End() { - ExecCMD(); + Draw(); for (auto &vdata : m_vertex_data) { diff --git a/rpcs3/Emu/RSX/RSXThread.h b/rpcs3/Emu/RSX/RSXThread.h index 7556f40565..aa3f74e83f 100644 --- a/rpcs3/Emu/RSX/RSXThread.h +++ b/rpcs3/Emu/RSX/RSXThread.h @@ -343,8 +343,11 @@ public: s32 m_color_conv_dtdy; // Semaphore - bool m_set_semaphore_offset; - u32 m_semaphore_offset; + // PGRAPH + u32 m_PGRAPH_semaphore_offset; + //PFIFO + u32 m_PFIFO_semaphore_offset; + u32 m_PFIFO_semaphore_release_value; // Fog bool m_set_fog_mode; @@ -597,7 +600,6 @@ protected: m_set_line_width = false; m_set_line_smooth = false; m_set_shade_mode = false; - m_set_semaphore_offset = false; m_set_fog_mode = false; m_set_fog_params = false; m_set_clip_plane = false; @@ -644,10 +646,46 @@ protected: virtual void OnInitThread() = 0; virtual void OnExitThread() = 0; virtual void OnReset() = 0; - virtual void ExecCMD() = 0; - virtual void ExecCMD(u32 cmd) = 0; + + /** + * This member is called when the backend is expected to render a draw call, either + * indexed or not. + */ + virtual void Draw() = 0; + + /** + * This member is called when the backend is expected to clear a target surface. + */ + virtual void Clear(u32 cmd) = 0; + + /** + * This member is called when the backend is expected to present a target surface in + * either local or main memory. + */ virtual void Flip() = 0; + /** + * This member is called when RSXThread parse a TEXTURE_READ_SEMAPHORE_RELEASE + * command. + * Backend is expected to write value at offset when current draw textures aren't + * needed anymore by the GPU and can be modified. + */ + virtual void semaphorePGRAPHTextureReadRelease(u32 offset, u32 value) = 0; + /** + * This member is called when RSXThread parse a BACK_END_WRITE_SEMAPHORE_RELEASE + * command. + * Backend is expected to write value at offset when current draw call has completed + * and render surface can be used. + */ + virtual void semaphorePGRAPHBackendRelease(u32 offset, u32 value) = 0; + /** + * This member is called when RSXThread parse a SEMAPHORE_ACQUIRE command. + * Backend and associated GPU is expected to wait that memory at offset is the same + * as value. In particular buffer/texture buffers value can change while backend is + * waiting. + */ + virtual void semaphorePFIFOAcquire(u32 offset, u32 value) = 0; + void LoadVertexData(u32 first, u32 count) { for (u32 i = 0; i < m_vertex_count; ++i)