diff --git a/.gitignore b/.gitignore index 0051e90efb..a03567402d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,10 @@ /bin/*.exp rpcs3/git-version.h +# Visual Studio Profiler Files +*.vspx +*.psess + # Copyrighted files /bin/data/ /bin/dev_flash/data/font diff --git a/rpcs3.sln b/rpcs3.sln index 6da2bb9f4d..9c53b05c10 100644 --- a/rpcs3.sln +++ b/rpcs3.sln @@ -460,4 +460,7 @@ Global {74827EBD-93DC-5110-BA95-3F2AB029B6B0} = {5812E712-6213-4372-B095-9EB9BAA1F2DF} {AC40FF01-426E-4838-A317-66354CEFAE88} = {E2A982F2-4B1A-48B1-8D77-A17A589C58D7} EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/rpcs3/Emu/Cell/PPUDisAsm.h b/rpcs3/Emu/Cell/PPUDisAsm.h index 8682e3564d..102f30dd78 100644 --- a/rpcs3/Emu/Cell/PPUDisAsm.h +++ b/rpcs3/Emu/Cell/PPUDisAsm.h @@ -1788,9 +1788,9 @@ private: { DisAsm_R2("icbi", ra, rb); } - void DCBZ(u32 ra, u32 rs) + void DCBZ(u32 ra, u32 rb) { - DisAsm_R2("dcbz", ra, rs); + DisAsm_R2("dcbz", ra, rb); } void LWZ(u32 rd, u32 ra, s32 d) { diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 421f7603a4..825a7dd74a 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -2084,9 +2084,10 @@ private: { if (CheckCondition(bo, bi)) { + const u64 nextLR = CPU.PC + 4; CPU.SetBranch(branchTarget((aa ? 0 : CPU.PC), bd), lk); + if(lk) CPU.LR = nextLR; } - if(lk) CPU.LR = CPU.PC + 4; } void SC(u32 sc_code) { @@ -2108,8 +2109,9 @@ private: } void B(s32 ll, u32 aa, u32 lk) { + const u64 nextLR = CPU.PC + 4; CPU.SetBranch(branchTarget(aa ? 0 : CPU.PC, ll), lk); - if(lk) CPU.LR = CPU.PC + 4; + if(lk) CPU.LR = nextLR; } void MCRF(u32 crfd, u32 crfs) { @@ -2119,9 +2121,10 @@ private: { if (CheckCondition(bo, bi)) { + const u64 nextLR = CPU.PC + 4; CPU.SetBranch(branchTarget(0, CPU.LR), true); + if(lk) CPU.LR = nextLR; } - if(lk) CPU.LR = CPU.PC + 4; } void CRNOR(u32 crbd, u32 crba, u32 crbb) { @@ -2171,9 +2174,10 @@ private: { if(bo & 0x10 || CPU.IsCR(bi) == (bo & 0x8)) { + const u64 nextLR = CPU.PC + 4; CPU.SetBranch(branchTarget(0, CPU.CTR), true); + if(lk) CPU.LR = nextLR; } - if(lk) CPU.LR = CPU.PC + 4; } void RLWIMI(u32 ra, u32 rs, u32 sh, u32 mb, u32 me, bool rc) { @@ -2816,7 +2820,6 @@ private: const u64 RA = CPU.GPR[ra]; const u64 RB = CPU.GPR[rb]; CPU.GPR[rd] = RA + RB; - CPU.XER.CA = CPU.IsCarry(RA, RB); if(oe) UNK("addo"); if(rc) CPU.UpdateCR0(CPU.GPR[rd]); } @@ -3288,16 +3291,18 @@ private: void EXTSW(u32 ra, u32 rs, bool rc) { CPU.GPR[ra] = (s64)(s32)CPU.GPR[rs]; - //CPU.XER.CA = ((s64)CPU.GPR[ra] < 0); // ??? if(rc) CPU.UpdateCR0(CPU.GPR[ra]); } void ICBI(u32 ra, u32 rs) { // Clear jit for the specified block? Nothing to do in the interpreter. } - void DCBZ(u32 ra, u32 rs) + void DCBZ(u32 ra, u32 rb) { - //UNK("dcbz", false); + const u64 addr = ra ? CPU.GPR[ra] + CPU.GPR[rb] : CPU.GPR[rb]; + u8 *const cache_line = Memory.GetMemFromAddr(addr & ~127); + if (cache_line) + memset(cache_line, 0, 128); _mm_mfence(); } void LWZ(u32 rd, u32 ra, s32 d) diff --git a/rpcs3/Emu/GS/GL/GLGSRender.cpp b/rpcs3/Emu/GS/GL/GLGSRender.cpp index 21f62b562a..26df787b92 100644 --- a/rpcs3/Emu/GS/GL/GLGSRender.cpp +++ b/rpcs3/Emu/GS/GL/GLGSRender.cpp @@ -581,7 +581,7 @@ void GLGSRender::WriteColourBufferD() checkForGlError("glReadPixels(GL_RGBA, GL_UNSIGNED_INT_8_8_8_8)"); } -void GLGSRender::WriteBuffers() +void GLGSRender::WriteColorBuffers() { glPixelStorei(GL_PACK_ROW_LENGTH, 0); glPixelStorei(GL_PACK_ALIGNMENT, 4); @@ -641,7 +641,6 @@ void GLGSRender::OnInitThread() InitProcTable(); glEnable(GL_TEXTURE_2D); - glEnable(GL_SCISSOR_TEST); #ifdef _WIN32 glSwapInterval(Ini.GSVSyncEnable.GetValue() ? 1 : 0); @@ -773,8 +772,10 @@ void GLGSRender::ExecCMD() } m_fbo.Bind(); + if(Ini.GSDumpDepthBuffer.GetValue()) WriteDepthBuffer(); + static const GLenum draw_buffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; switch(m_surface_colour_target) @@ -813,20 +814,12 @@ void GLGSRender::ExecCMD() checkForGlError("glColorMask"); } - //glFrontFace(m_front_face); - if(m_set_viewport_horizontal && m_set_viewport_vertical) { //glViewport(m_viewport_x, m_viewport_y, m_viewport_w, m_viewport_h); //checkForGlError("glViewport"); } - if(m_set_scissor_horizontal && m_set_scissor_vertical) - { - glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); - checkForGlError("glScissor"); - } - if(m_clear_surface_mask) { GLbitfield f = 0; @@ -859,18 +852,6 @@ void GLGSRender::ExecCMD() glClear(f); } - if(m_set_front_polygon_mode) - { - glPolygonMode(GL_FRONT, m_front_polygon_mode); - checkForGlError("glPolygonMode(Front)"); - } - - if (m_set_back_polygon_mode) - { - glPolygonMode(GL_BACK, m_back_polygon_mode); - checkForGlError("glPolygonMode(Back)"); - } - Enable(m_depth_test_enable, GL_DEPTH_TEST); Enable(m_set_alpha_test, GL_ALPHA_TEST); Enable(m_set_depth_bounds_test, GL_DEPTH_BOUNDS_TEST_EXT); @@ -879,12 +860,13 @@ void GLGSRender::ExecCMD() Enable(m_set_cull_face_enable, GL_CULL_FACE); Enable(m_set_dither, GL_DITHER); Enable(m_set_stencil_test, GL_STENCIL_TEST); + Enable(m_set_scissor_horizontal && m_set_scissor_vertical, GL_SCISSOR_TEST); Enable(m_set_line_smooth, GL_LINE_SMOOTH); Enable(m_set_poly_smooth, GL_POLYGON_SMOOTH); Enable(m_set_poly_offset_fill, GL_POLYGON_OFFSET_FILL); Enable(m_set_poly_offset_line, GL_POLYGON_OFFSET_LINE); Enable(m_set_poly_offset_point, GL_POLYGON_OFFSET_POINT); - //Enable(m_set_restart_index, GL_PRIMITIVE_RESTART); //Requires OpenGL 3.1+ + //Enable(m_set_restart_index, GL_PRIMITIVE_RESTART); // Requires OpenGL 3.1+ if(m_set_clip_plane) { @@ -900,6 +882,37 @@ void GLGSRender::ExecCMD() checkForGlError("glEnable"); + + if (m_set_front_polygon_mode) + { + glPolygonMode(GL_FRONT, m_front_polygon_mode); + checkForGlError("glPolygonMode(Front)"); + } + + if (m_set_back_polygon_mode) + { + glPolygonMode(GL_BACK, m_back_polygon_mode); + checkForGlError("glPolygonMode(Back)"); + } + + if (m_set_poly_offset_scale_factor && m_set_poly_offset_bias) + { + glPolygonOffset(m_set_poly_offset_scale_factor, m_set_poly_offset_bias); + checkForGlError("glPolygonOffset"); + } + + if (m_set_logic_op) + { + glLogicOp(m_logic_op); + checkForGlError("glLogicOp"); + } + + if (m_set_scissor_horizontal && m_set_scissor_vertical) + { + glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); + checkForGlError("glScissor"); + } + if(m_set_two_sided_stencil_test_enable) { if(m_set_stencil_fail && m_set_stencil_zfail && m_set_stencil_zpass) @@ -1022,6 +1035,16 @@ void GLGSRender::ExecCMD() checkForGlError("glCullFace"); } + if (m_set_front_face) + { + // Sanity check . Disgaea 3 return 0x1d0 here and cause openGL 0x0500 + if (m_front_face == GL_CW || m_front_face == GL_CCW) + { + glFrontFace(m_front_face); + checkForGlError("glFrontFace"); + } + } + if(m_set_alpha_func && m_set_alpha_ref) { glAlphaFunc(m_alpha_func, m_alpha_ref/255.0f); @@ -1045,7 +1068,7 @@ void GLGSRender::ExecCMD() if(m_set_restart_index) { ConLog.Warning("m_set_restart_index requires glPrimitiveRestartIndex()"); - //glPrimitiveRestartIndex(m_restart_index); //Requires OpenGL 3.1+ + //glPrimitiveRestartIndex(m_restart_index); // Requires OpenGL 3.1+ //checkForGlError("glPrimitiveRestartIndex"); } @@ -1110,12 +1133,34 @@ void GLGSRender::ExecCMD() DisableVertexData(); } - if(Ini.GSDumpColorBuffers.GetValue()) - WriteBuffers(); + if (Ini.GSDumpColorBuffers.GetValue()) + WriteColorBuffers(); } void GLGSRender::Flip() { + // Fast path for non-MRT using glBlitFramebuffer + // TODO: check for MRT samples + if (m_fbo.IsCreated() && (m_surface_colour_target == CELL_GCM_SURFACE_TARGET_0 || m_surface_colour_target == CELL_GCM_SURFACE_TARGET_1)) + { + GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0); + // Renderbuffer is upside turn , swapped srcY0 and srcY1 + GLfbo::Blit(0, RSXThread::m_height, RSXThread::m_width, 0, 0, 0, RSXThread::m_width, RSXThread::m_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + m_fbo.Bind(); + + for (uint i = 0; iFlip(m_context); + + m_fbo.Bind(); + + return; + } + if(m_set_scissor_horizontal && m_set_scissor_vertical) { glScissor(0, 0, RSXThread::m_width, RSXThread::m_height); @@ -1205,24 +1250,6 @@ void GLGSRender::Flip() glEnd(); } - /*GLfbo::Bind(GL_DRAW_FRAMEBUFFER, 0); - GLfbo::Blit( - m_surface_clip_x, m_surface_clip_y, m_surface_clip_x + m_surface_clip_w, m_surface_clip_y + m_surface_clip_h, - m_surface_clip_x, m_surface_clip_y, m_surface_clip_x + m_surface_clip_w, m_surface_clip_y + m_surface_clip_h, - GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST);*/ - if(m_fbo.IsCreated()) - m_fbo.Bind(); - - for(uint i=0; iFlip(m_context); - - if(m_fbo.IsCreated()) - m_fbo.Bind(); - if(m_set_scissor_horizontal && m_set_scissor_vertical) { glScissor(m_scissor_x, m_scissor_y, m_scissor_w, m_scissor_h); diff --git a/rpcs3/Emu/GS/GL/GLGSRender.h b/rpcs3/Emu/GS/GL/GLGSRender.h index 819d95ff1c..8839d578ea 100644 --- a/rpcs3/Emu/GS/GL/GLGSRender.h +++ b/rpcs3/Emu/GS/GL/GLGSRender.h @@ -827,11 +827,11 @@ private: virtual void Close(); bool LoadProgram(); void WriteDepthBuffer(); + void WriteColorBuffers(); void WriteColourBufferA(); void WriteColourBufferB(); void WriteColourBufferC(); void WriteColourBufferD(); - void WriteBuffers(); void DrawObjects(); diff --git a/rpcs3/Emu/GS/RSXThread.cpp b/rpcs3/Emu/GS/RSXThread.cpp index 814684b30c..13115f43a6 100644 --- a/rpcs3/Emu/GS/RSXThread.cpp +++ b/rpcs3/Emu/GS/RSXThread.cpp @@ -11,7 +11,10 @@ u32 GetAddress(u32 offset, u8 location) switch(location) { case CELL_GCM_LOCATION_LOCAL: return Memory.RSXFBMem.GetStartAddr() + offset; - case CELL_GCM_LOCATION_MAIN: return Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + offset); + case CELL_GCM_LOCATION_MAIN: + u64 realAddr; + Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + offset, realAddr); // TODO: Error Check? + return realAddr; } ConLog.Error("GetAddress(offset=0x%x, location=0x%x)", location); @@ -762,6 +765,10 @@ void RSXThread::DoCmd(const u32 fcmd, const u32 cmd, mem32_ptr_t& args, const u3 m_set_logic_op = ARGS(0) ? true : false; break; + case NV4097_SET_LOGIC_OP: + m_logic_op = ARGS(0); + break; + case NV4097_SET_CULL_FACE_ENABLE: m_set_cull_face_enable = ARGS(0) ? true : false; break; diff --git a/rpcs3/Emu/GS/RSXThread.h b/rpcs3/Emu/GS/RSXThread.h index 7d1e503882..1b2a675002 100644 --- a/rpcs3/Emu/GS/RSXThread.h +++ b/rpcs3/Emu/GS/RSXThread.h @@ -166,7 +166,6 @@ public: bool m_set_blend; bool m_set_depth_bounds_test; bool m_depth_test_enable; - bool m_set_logic_op; bool m_set_cull_face_enable; bool m_set_dither; bool m_set_stencil_test; @@ -176,6 +175,11 @@ public: bool m_set_poly_offset_line; bool m_set_poly_offset_point; + bool m_set_poly_offset_scale_factor; + u32 m_poly_offset_scale_factor; + bool m_set_poly_offset_bias; + u32 m_poly_offset_bias; + bool m_set_restart_index; u32 m_restart_index; @@ -198,6 +202,9 @@ public: bool m_set_back_polygon_mode; u32 m_back_polygon_mode; + bool m_set_logic_op; + u32 m_logic_op; + u32 m_clear_surface_mask; u32 m_clear_surface_z; u8 m_clear_surface_s; @@ -382,6 +389,7 @@ public: u32 m_surface_colour_target; + bool m_set_front_face; u32 m_front_face; u8 m_begin_end; @@ -426,6 +434,9 @@ protected: m_clear_z = 0xffffff; m_clear_s = 0; + m_poly_offset_scale_factor = 0; + m_poly_offset_bias = 0; + m_depth_bounds_min = 0.0; m_depth_bounds_max = 1.0; m_restart_index = 0xffffffff; @@ -498,6 +509,8 @@ protected: m_set_poly_offset_fill = false; m_set_poly_offset_line = false; m_set_poly_offset_point = false; + m_set_poly_offset_scale_factor = false; + m_set_poly_offset_bias = false; m_set_restart_index = false; m_clear_surface_mask = 0; diff --git a/rpcs3/Emu/GS/sysutil_video.h b/rpcs3/Emu/GS/sysutil_video.h index ce92847a29..3488427c25 100644 --- a/rpcs3/Emu/GS/sysutil_video.h +++ b/rpcs3/Emu/GS/sysutil_video.h @@ -232,6 +232,7 @@ static const CellVideoOutResolution ResolutionTable[] = {1440, 1080}, //11 - 6 {1280, 1080}, //12 - 7 {960, 1080}, //13 - 8 + {960, 540}, //14 - 9 }; inline static u32 ResolutionIdToNum(u32 id) @@ -252,9 +253,10 @@ inline static u32 ResolutionIdToNum(u32 id) 6, //11 7, //12 8, //13 + 9, //14 }; - return id <= 13 ? res[id] : 0; + return id <= 14 ? res[id] : 0; } inline static u32 ResolutionNumToId(u32 num) @@ -270,7 +272,8 @@ inline static u32 ResolutionNumToId(u32 num) 11, 12, 13, + 14, }; - return num <= 8 ? res[num] : 0; + return num <= 9 ? res[num] : 0; } diff --git a/rpcs3/Emu/Io/Pad.cpp b/rpcs3/Emu/Io/Pad.cpp index 1dde2828c3..48e9e67f46 100644 --- a/rpcs3/Emu/Io/Pad.cpp +++ b/rpcs3/Emu/Io/Pad.cpp @@ -2,6 +2,9 @@ #include "Pad.h" #include "Null/NullPadHandler.h" #include "Windows/WindowsPadHandler.h" +#if defined(_WIN32) +#include "XInput/XInputPadHandler.h" +#endif PadManager::PadManager() : m_pad_handler(nullptr) @@ -25,6 +28,12 @@ void PadManager::Init(const u32 max_connect) m_pad_handler.reset(new WindowsPadHandler()); break; +#if defined(_WIN32) + case 2: + m_pad_handler.reset(new XInputPadHandler()); + break; +#endif + default: case 0: m_pad_handler.reset(new NullPadHandler()); diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 050a5fce3f..104af38a86 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -220,7 +220,7 @@ public: virtual ~PadHandlerBase() = default; //Set value to set pressure/axi to certain level, otherwise 0/255 default - void Key(const u32 code, bool pressed, u16 value=256) + void Key(const u32 code, bool pressed, u16 value=255) { for(Pad& pad : m_pads) { diff --git a/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp b/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp new file mode 100644 index 0000000000..4dcad1e056 --- /dev/null +++ b/rpcs3/Emu/Io/XInput/XInputPadHandler.cpp @@ -0,0 +1,181 @@ +#include "stdafx.h" +#if defined (_WIN32) +#include "XInputPadHandler.h" +#include + +namespace { + const DWORD THREAD_TIMEOUT = 1000; + const DWORD THREAD_SLEEP = 10; + const DWORD THREAD_SLEEP_INACTIVE = 100; + const DWORD MAX_GAMEPADS = 4; + const DWORD XINPUT_GAMEPAD_GUIDE = 0x0400; + const DWORD XINPUT_GAMEPAD_BUTTONS = 16; + const LPCWSTR LIBRARY_FILENAMES[] = { + L"xinput1_4.dll", + L"xinput1_3.dll", + L"xinput1_2.dll", + L"xinput9_1_0.dll" + }; + + inline u16 ConvertAxis(SHORT value) + { + return static_cast((value + 32768l) >> 8); + } +} + +XInputPadHandler::XInputPadHandler() : active(false), thread(nullptr), library(nullptr), xinputGetState(nullptr), xinputEnable(nullptr) +{ +} + +XInputPadHandler::~XInputPadHandler() +{ + Close(); +} + +void XInputPadHandler::Init(const u32 max_connect) +{ + for (auto it : LIBRARY_FILENAMES) + { + library = LoadLibrary(it); + if (library) + { + xinputEnable = reinterpret_cast(GetProcAddress(library, "XInputEnable")); + xinputGetState = reinterpret_cast(GetProcAddress(library, reinterpret_cast(100))); + if (!xinputGetState) + { + xinputGetState = reinterpret_cast(GetProcAddress(library, "XInputGetState")); + } + + if (xinputEnable && xinputGetState) + { + break; + } + + FreeLibrary(library); + library = nullptr; + xinputEnable = nullptr; + xinputGetState = nullptr; + } + } + + if (library) + { + std::memset(&m_info, 0, sizeof m_info); + m_info.max_connect = max_connect; + + for (u32 i = 0, max = std::min(max_connect, u32(MAX_GAMEPADS)); i != max; ++i) + { + m_pads.emplace_back( + CELL_PAD_STATUS_ASSIGN_CHANGES, + CELL_PAD_SETTING_PRESS_OFF | CELL_PAD_SETTING_SENSOR_OFF, + CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE, + CELL_PAD_DEV_TYPE_STANDARD + ); + auto & pad = m_pads.back(); + + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_UP, CELL_PAD_CTRL_UP); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_DOWN, CELL_PAD_CTRL_DOWN); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_LEFT, CELL_PAD_CTRL_LEFT); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_DPAD_RIGHT, CELL_PAD_CTRL_RIGHT); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_START, CELL_PAD_CTRL_START); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_BACK, CELL_PAD_CTRL_SELECT); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_LEFT_THUMB, CELL_PAD_CTRL_L3); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL1, XINPUT_GAMEPAD_RIGHT_THUMB, CELL_PAD_CTRL_R3); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_LEFT_SHOULDER, CELL_PAD_CTRL_L1); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_RIGHT_SHOULDER, CELL_PAD_CTRL_R1); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_GUIDE, 0x100/*CELL_PAD_CTRL_PS*/);// TODO: PS button support + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, 0x0); // Reserved + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_A, CELL_PAD_CTRL_CROSS); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_B, CELL_PAD_CTRL_CIRCLE); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_X, CELL_PAD_CTRL_SQUARE); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, XINPUT_GAMEPAD_Y, CELL_PAD_CTRL_TRIANGLE); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_L2); + pad.m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_DIGITAL2, 0, CELL_PAD_CTRL_R2); + + pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, 0, 0); + pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, 0, 0); + pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, 0, 0); + pad.m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, 0, 0); + } + + active = true; + thread = CreateThread(NULL, 0, &XInputPadHandler::ThreadProcProxy, this, 0, NULL); + } +} + +void XInputPadHandler::Close() +{ + if (library) + { + if (thread) + { + active = false; + if (WaitForSingleObject(thread, THREAD_TIMEOUT) != WAIT_OBJECT_0) + ConLog.Error("XInput thread could not stop within %d milliseconds", THREAD_TIMEOUT); + thread = nullptr; + } + + FreeLibrary(library); + library = nullptr; + xinputGetState = nullptr; + xinputEnable = nullptr; + } + + m_pads.clear(); +} + +DWORD XInputPadHandler::ThreadProcedure() +{ + while (active) + { + XINPUT_STATE state; + DWORD result; + DWORD online = 0; + + for (DWORD i = 0; i != m_pads.size(); ++i) + { + auto & pad = m_pads[i]; + + result = (* xinputGetState)(i, &state); + switch (result) + { + case ERROR_DEVICE_NOT_CONNECTED: + pad.m_port_status &= ~CELL_PAD_STATUS_CONNECTED; + break; + + case ERROR_SUCCESS: + ++online; + pad.m_port_status |= CELL_PAD_STATUS_CONNECTED; + for (DWORD j = 0; j != XINPUT_GAMEPAD_BUTTONS; ++j) + { + bool pressed = state.Gamepad.wButtons & (1 << j); + pad.m_buttons[j].m_pressed = pressed; + pad.m_buttons[j].m_value = pressed ? 255 : 0; + } + + pad.m_buttons[XINPUT_GAMEPAD_BUTTONS].m_pressed = state.Gamepad.bLeftTrigger > 0; + pad.m_buttons[XINPUT_GAMEPAD_BUTTONS].m_value = state.Gamepad.bLeftTrigger; + pad.m_buttons[XINPUT_GAMEPAD_BUTTONS + 1].m_pressed = state.Gamepad.bRightTrigger > 0; + pad.m_buttons[XINPUT_GAMEPAD_BUTTONS + 1].m_value = state.Gamepad.bRightTrigger; + + pad.m_sticks[0].m_value = ConvertAxis(state.Gamepad.sThumbLX); + pad.m_sticks[1].m_value = ConvertAxis(state.Gamepad.sThumbLY); + pad.m_sticks[2].m_value = ConvertAxis(state.Gamepad.sThumbRX); + pad.m_sticks[3].m_value = ConvertAxis(state.Gamepad.sThumbRY); + break; + } + } + + Sleep((online > 0) ? THREAD_SLEEP : THREAD_SLEEP_INACTIVE); + m_info.now_connect = online; + } + + return 0; +} + +DWORD WINAPI XInputPadHandler::ThreadProcProxy(LPVOID parameter) +{ + return reinterpret_cast(parameter)->ThreadProcedure(); +} + +#endif \ No newline at end of file diff --git a/rpcs3/Emu/Io/XInput/XInputPadHandler.h b/rpcs3/Emu/Io/XInput/XInputPadHandler.h new file mode 100644 index 0000000000..ef1db245cb --- /dev/null +++ b/rpcs3/Emu/Io/XInput/XInputPadHandler.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Emu/Io/PadHandler.h" +#include + +class XInputPadHandler : public PadHandlerBase +{ +public: + XInputPadHandler(); + ~XInputPadHandler(); + + void Init(const u32 max_connect) override; + void Close() override; + +private: + typedef void (WINAPI * PFN_XINPUTENABLE)(BOOL); + typedef DWORD (WINAPI * PFN_XINPUTGETSTATE)(DWORD, XINPUT_STATE *); + +private: + DWORD ThreadProcedure(); + static DWORD WINAPI ThreadProcProxy(LPVOID parameter); + +private: + mutable bool active; + HANDLE thread; + HMODULE library; + PFN_XINPUTGETSTATE xinputGetState; + PFN_XINPUTENABLE xinputEnable; + +}; diff --git a/rpcs3/Emu/Memory/Memory.cpp b/rpcs3/Emu/Memory/Memory.cpp index cc1c3add1a..7a1ca1e8b2 100644 --- a/rpcs3/Emu/Memory/Memory.cpp +++ b/rpcs3/Emu/Memory/Memory.cpp @@ -614,21 +614,25 @@ u32 VirtualMemoryBlock::UnmapAddress(u64 addr) bool VirtualMemoryBlock::Read8(const u64 addr, u8* value) { u64 realAddr; - *value = Memory.Read8(realAddr = getRealAddr(addr)); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + *value = Memory.Read8(realAddr); + return true; } bool VirtualMemoryBlock::Read16(const u64 addr, u16* value) { u64 realAddr; - *value = Memory.Read16(realAddr = getRealAddr(addr)); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + *value = Memory.Read16(realAddr); + return true; } bool VirtualMemoryBlock::Read32(const u64 addr, u32* value) { - u64 realAddr = getRealAddr(addr); - if (realAddr == 0) + u64 realAddr; + if (!getRealAddr(addr, realAddr)) return false; *value = Memory.Read32(realAddr); return true; @@ -637,63 +641,78 @@ bool VirtualMemoryBlock::Read32(const u64 addr, u32* value) bool VirtualMemoryBlock::Read64(const u64 addr, u64* value) { u64 realAddr; - *value = Memory.Read64(realAddr = getRealAddr(addr)); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + *value = Memory.Read64(realAddr); + return true; } bool VirtualMemoryBlock::Read128(const u64 addr, u128* value) { u64 realAddr; - *value = Memory.Read128(realAddr = getRealAddr(addr)); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + *value = Memory.Read128(realAddr); + return true; } bool VirtualMemoryBlock::Write8(const u64 addr, const u8 value) { u64 realAddr; - Memory.Write8(realAddr = getRealAddr(addr), value); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + Memory.Write8(realAddr, value); + return true; } bool VirtualMemoryBlock::Write16(const u64 addr, const u16 value) { u64 realAddr; - Memory.Write16(realAddr = getRealAddr(addr), value); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + Memory.Write16(realAddr, value); + return true; } bool VirtualMemoryBlock::Write32(const u64 addr, const u32 value) { u64 realAddr; - Memory.Write32(realAddr = getRealAddr(addr), value); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + Memory.Write32(realAddr, value); + return true; } bool VirtualMemoryBlock::Write64(const u64 addr, const u64 value) { u64 realAddr; - Memory.Write64(realAddr = getRealAddr(addr), value); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + Memory.Write64(realAddr, value); + return true; } bool VirtualMemoryBlock::Write128(const u64 addr, const u128 value) { u64 realAddr; - Memory.Write128(realAddr = getRealAddr(addr), value); - return realAddr != 0; + if(!getRealAddr(addr, realAddr)) + return false; + Memory.Write128(realAddr, value); + return true; } -u64 VirtualMemoryBlock::getRealAddr(u64 addr) +bool VirtualMemoryBlock::getRealAddr(u64 addr, u64& result) { for(u32 i=0; i= m_mapped_memory[i].addr && addr < m_mapped_memory[i].addr + m_mapped_memory[i].size) { - return m_mapped_memory[i].realAddress + (addr - m_mapped_memory[i].addr); + result = m_mapped_memory[i].realAddress + (addr - m_mapped_memory[i].addr); + return true; } } - return 0; + return false; } u64 VirtualMemoryBlock::getMappedAddress(u64 realAddress) diff --git a/rpcs3/Emu/Memory/Memory.h b/rpcs3/Emu/Memory/Memory.h index d1dcef50e2..e5d56a111c 100644 --- a/rpcs3/Emu/Memory/Memory.h +++ b/rpcs3/Emu/Memory/Memory.h @@ -333,11 +333,11 @@ public: return true; } - bool CopyFromReal(u32 to, void* real, u32 count) // (4K pages) copy from real to virtual memory + bool CopyFromReal(u32 to, const void* real, u32 count) // (4K pages) copy from real to virtual memory { if (!count) return true; - u8* from = (u8*)real; + const u8* from = (const u8*)real; if (u32 frag = to & 4095) { @@ -795,6 +795,12 @@ public: return this->m_addr; } + u32 AppendRawBytes(const u8 * bytes, size_t count) { + Memory.CopyFromReal(this->m_addr, bytes, count); + this->m_addr += count; + return this->m_addr; + } + u32 Skip(const u32 offset) { return this->m_addr += offset; } operator be_t*() { return GetPtr(); } diff --git a/rpcs3/Emu/Memory/MemoryBlock.h b/rpcs3/Emu/Memory/MemoryBlock.h index 144055716c..1709214878 100644 --- a/rpcs3/Emu/Memory/MemoryBlock.h +++ b/rpcs3/Emu/Memory/MemoryBlock.h @@ -281,8 +281,9 @@ public: virtual bool Write64(const u64 addr, const u64 value); virtual bool Write128(const u64 addr, const u128 value); - // return the real address given a mapped address, if not mapped return 0 - u64 getRealAddr(u64 addr); + // try to get the real address given a mapped address + // return true for success + bool getRealAddr(u64 addr, u64& result); // return the mapped address given a real address, if not mapped return 0 u64 getMappedAddress(u64 realAddress); diff --git a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp index 2a463daa48..55a01b8af2 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellGcmSys.cpp @@ -339,16 +339,16 @@ int cellGcmSetPrepareFlip(mem_ptr_t ctxt, u32 id) { ConLog.Warning("bad flip!"); //cellGcmCallback(ctxt.GetAddr(), current + 8 - end); - //copied: + //copied: - CellGcmControl& ctrl = (CellGcmControl&)Memory[gcm_info.control_addr]; + CellGcmControl& ctrl = (CellGcmControl&)Memory[gcm_info.control_addr]; - const s32 res = ctxt->current - ctxt->begin - ctrl.put; + const s32 res = ctxt->current - ctxt->begin - ctrl.put; - if(res > 0) Memory.Copy(ctxt->begin, ctxt->current - res, res); - ctxt->current = ctxt->begin + res; - ctrl.put = res; - ctrl.get = 0; + if(res > 0) Memory.Copy(ctxt->begin, ctxt->current - res, res); + ctxt->current = ctxt->begin + res; + ctrl.put = res; + ctrl.get = 0; } current = ctxt->current; @@ -575,9 +575,7 @@ int32_t cellGcmIoOffsetToAddress(u32 ioOffset, u64 address) { u64 realAddr; - realAddr = Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ioOffset); - - if (!realAddr) + if (!Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ioOffset, realAddr)) return CELL_GCM_ERROR_FAILURE; Memory.Write64(address, realAddr); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp index 617676d2aa..9d134b1127 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPamf.cpp @@ -169,6 +169,10 @@ int cellPamfVerify(mem_ptr_t pAddr, u64 fileSize) int cellPamfReaderInitialize(mem_ptr_t pSelf, mem_ptr_t pAddr, u64 fileSize, u32 attribute) { + // Skip PAMF initialization + if (Ini.SkipPamf.GetValue()) + return -1; + cellPamf.Warning("cellPamfReaderInitialize(pSelf=0x%x, pAddr=0x%x, fileSize=%d, attribute=0x%x)", pSelf.GetAddr(), pAddr.GetAddr(), fileSize, attribute); diff --git a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp index d169321c51..31886ab113 100644 --- a/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp +++ b/rpcs3/Emu/SysCalls/Modules/cellPngDec.cpp @@ -201,7 +201,7 @@ int cellPngDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m case CELL_PNGDEC_ARGB: { - const char nComponents = 4; + const int nComponents = 4; image_size *= nComponents; if (bytesPerLine > width * nComponents || flip) //check if we need padding { @@ -225,13 +225,19 @@ int cellPngDecDecodeData(u32 mainHandle, u32 subHandle, mem8_ptr_t data, const m } else { - for (uint i = 0; i < image_size; i += nComponents) + uint* dest = (uint*)new char[image_size]; + uint* source_current = (uint*)&(image.get()[0]); + uint* dest_current = dest; + for (uint i = 0; i < image_size / nComponents; i++) { - data += image.get()[i + 3]; - data += image.get()[i + 0]; - data += image.get()[i + 1]; - data += image.get()[i + 2]; + uint val = *source_current; + *dest_current = (val >> 24) | (val << 8); // set alpha (A8) as leftmost byte + source_current++; + dest_current++; } + // NOTE: AppendRawBytes has diff side-effect vs Memory.CopyFromReal + data.AppendRawBytes((u8*)dest, image_size); + delete[] dest; } } break; diff --git a/rpcs3/Gui/MainFrame.cpp b/rpcs3/Gui/MainFrame.cpp index 302ee69650..2762c0988f 100644 --- a/rpcs3/Gui/MainFrame.cpp +++ b/rpcs3/Gui/MainFrame.cpp @@ -372,6 +372,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) wxCheckBox* chbox_gs_log_prog = new wxCheckBox(p_graphics, wxID_ANY, "Log vertex/fragment programs"); wxCheckBox* chbox_gs_dump_depth = new wxCheckBox(p_graphics, wxID_ANY, "Write Depth Buffer"); wxCheckBox* chbox_gs_dump_color = new wxCheckBox(p_graphics, wxID_ANY, "Write Color Buffers"); + wxCheckBox* chbox_skip_pamf = new wxCheckBox(p_graphics, wxID_ANY, "Skip Pamf"); wxCheckBox* chbox_gs_vsync = new wxCheckBox(p_graphics, wxID_ANY, "VSync"); wxCheckBox* chbox_audio_dump = new wxCheckBox(p_audio, wxID_ANY, "Dump to file"); wxCheckBox* chbox_hle_logging = new wxCheckBox(p_hle, wxID_ANY, "Log all SysCalls"); @@ -400,6 +401,9 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) cbox_pad_handler->Append("Null"); cbox_pad_handler->Append("Windows"); +#if defined (_WIN32) + cbox_pad_handler->Append("XInput"); +#endif //cbox_pad_handler->Append("DirectInput"); cbox_keyboard_handler->Append("Null"); @@ -444,6 +448,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) chbox_gs_log_prog ->SetValue(Ini.GSLogPrograms.GetValue()); chbox_gs_dump_depth ->SetValue(Ini.GSDumpDepthBuffer.GetValue()); chbox_gs_dump_color ->SetValue(Ini.GSDumpColorBuffers.GetValue()); + chbox_skip_pamf ->SetValue(Ini.SkipPamf.GetValue()); chbox_gs_vsync ->SetValue(Ini.GSVSyncEnable.GetValue()); chbox_audio_dump ->SetValue(Ini.AudioDumpToFile.GetValue()); chbox_hle_logging ->SetValue(Ini.HLELogging.GetValue()); @@ -499,6 +504,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) s_subpanel_graphics->Add(chbox_gs_log_prog, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_dump_depth, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_dump_color, wxSizerFlags().Border(wxALL, 5).Expand()); + s_subpanel_graphics->Add(chbox_skip_pamf, wxSizerFlags().Border(wxALL, 5).Expand()); s_subpanel_graphics->Add(chbox_gs_vsync, wxSizerFlags().Border(wxALL, 5).Expand()); // Input - Output @@ -548,6 +554,7 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event)) Ini.GSLogPrograms.SetValue(chbox_gs_log_prog->GetValue()); Ini.GSDumpDepthBuffer.SetValue(chbox_gs_dump_depth->GetValue()); Ini.GSDumpColorBuffers.SetValue(chbox_gs_dump_color->GetValue()); + Ini.SkipPamf.SetValue(chbox_skip_pamf->GetValue()); Ini.PadHandlerMode.SetValue(cbox_pad_handler->GetSelection()); Ini.KeyboardHandlerMode.SetValue(cbox_keyboard_handler->GetSelection()); Ini.MouseHandlerMode.SetValue(cbox_mouse_handler->GetSelection()); diff --git a/rpcs3/Gui/RSXDebugger.cpp b/rpcs3/Gui/RSXDebugger.cpp index 505f67395e..cdc5b31e50 100644 --- a/rpcs3/Gui/RSXDebugger.cpp +++ b/rpcs3/Gui/RSXDebugger.cpp @@ -322,20 +322,28 @@ void RSXDebugger::GoToGet(wxCommandEvent& event) { if (!RSXReady()) return; CellGcmControl* ctrl = (CellGcmControl*)&Memory[Emu.GetGSManager().GetRender().m_ctrlAddress]; - m_addr = Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ctrl->get); - t_addr->SetValue(wxString::Format("%08x", m_addr)); - UpdateInformation(); - event.Skip(); + u64 realAddr; + if (Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ctrl->get, realAddr)) { + m_addr = realAddr; // WARNING: Potential Truncation? Cast from u64 to u32 + t_addr->SetValue(wxString::Format("%08x", m_addr)); + UpdateInformation(); + event.Skip(); + } + // TODO: We should probably throw something? } void RSXDebugger::GoToPut(wxCommandEvent& event) { if (!RSXReady()) return; CellGcmControl* ctrl = (CellGcmControl*)&Memory[Emu.GetGSManager().GetRender().m_ctrlAddress]; - m_addr = Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ctrl->put); - t_addr->SetValue(wxString::Format("%08x", m_addr)); - UpdateInformation(); - event.Skip(); + u64 realAddr; + if (Memory.RSXIOMem.getRealAddr(Memory.RSXIOMem.GetStartAddr() + ctrl->put, realAddr)) { + m_addr = realAddr; // WARNING: Potential Truncation? Cast from u64 to u32 + t_addr->SetValue(wxString::Format("%08x", m_addr)); + UpdateInformation(); + event.Skip(); + } + // TODO: We should probably throw something? } void RSXDebugger::UpdateInformation() diff --git a/rpcs3/Ini.h b/rpcs3/Ini.h index 7bb4f282fa..7a75626086 100644 --- a/rpcs3/Ini.h +++ b/rpcs3/Ini.h @@ -117,6 +117,7 @@ public: IniEntry HLEExitOnStop; IniEntry HLELogLvl; IniEntry SysLanguage; + IniEntry SkipPamf; IniEntry PadHandlerLStickLeft; IniEntry PadHandlerLStickDown; @@ -161,6 +162,7 @@ public: GSLogPrograms.Init("LogPrograms", path); GSDumpColorBuffers.Init("DumpColorBuffers", path); GSDumpDepthBuffer.Init("DumpDepthBuffer", path); + SkipPamf.Init("SkipPamf", path); path = DefPath + "/" + "IO"; PadHandlerMode.Init("PadHandlerMode", path); @@ -221,6 +223,7 @@ public: GSLogPrograms.Load(false); GSDumpColorBuffers.Load(false); GSDumpDepthBuffer.Load(false); + SkipPamf.Load(false); PadHandlerMode.Load(1); KeyboardHandlerMode.Load(0); MouseHandlerMode.Load(0); @@ -271,6 +274,7 @@ public: GSLogPrograms.Save(); GSDumpColorBuffers.Save(); GSDumpDepthBuffer.Save(); + SkipPamf.Save(); PadHandlerMode.Save(); KeyboardHandlerMode.Save(); MouseHandlerMode.Save(); diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index 0a2f99be47..4ac2b51db7 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -350,6 +350,7 @@ + @@ -544,6 +545,7 @@ + diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index e16c56bc86..c949f78f34 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -71,6 +71,9 @@ {899523fa-c26a-44ea-b272-73c4585e3821} + + {a77ab520-4399-4c95-a7ee-985c9a5ad694} + @@ -505,6 +508,9 @@ Crypto + + Emu\Io\XInput + @@ -990,5 +996,8 @@ Gui + + Emu\Io\XInput + \ No newline at end of file